From c2367b41afe38f4e2f78544e1552e4f93302392a Mon Sep 17 00:00:00 2001 From: George Hazan Date: Thu, 2 Jul 2015 20:26:28 +0000 Subject: tray menu functions also moved to the core. now all menu items are gathered there git-svn-id: http://svn.miranda-ng.org/main/trunk@14476 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- src/mir_app/src/clistmenus.cpp | 1202 ------------------------------------- src/mir_app/src/clistmod.cpp | 2 - src/mir_app/src/framesmenu.cpp | 111 ---- src/mir_app/src/genmenu.cpp | 1199 ------------------------------------- src/mir_app/src/genmenuopt.cpp | 501 ---------------- src/mir_app/src/groupmenu.cpp | 250 -------- src/mir_app/src/menu_clist.cpp | 1206 ++++++++++++++++++++++++++++++++++++++ src/mir_app/src/menu_frames.cpp | 113 ++++ src/mir_app/src/menu_groups.cpp | 250 ++++++++ src/mir_app/src/menu_options.cpp | 501 ++++++++++++++++ src/mir_app/src/menu_tray.cpp | 80 +++ src/mir_app/src/menu_utils.cpp | 1199 +++++++++++++++++++++++++++++++++++++ src/mir_app/src/mir_app.def | 2 + src/mir_app/src/mir_app64.def | 2 + 14 files changed, 3353 insertions(+), 3265 deletions(-) delete mode 100644 src/mir_app/src/clistmenus.cpp delete mode 100644 src/mir_app/src/framesmenu.cpp delete mode 100644 src/mir_app/src/genmenu.cpp delete mode 100644 src/mir_app/src/genmenuopt.cpp delete mode 100644 src/mir_app/src/groupmenu.cpp create mode 100644 src/mir_app/src/menu_clist.cpp create mode 100644 src/mir_app/src/menu_frames.cpp create mode 100644 src/mir_app/src/menu_groups.cpp create mode 100644 src/mir_app/src/menu_options.cpp create mode 100644 src/mir_app/src/menu_tray.cpp create mode 100644 src/mir_app/src/menu_utils.cpp (limited to 'src') diff --git a/src/mir_app/src/clistmenus.cpp b/src/mir_app/src/clistmenus.cpp deleted file mode 100644 index 517feaef52..0000000000 --- a/src/mir_app/src/clistmenus.cpp +++ /dev/null @@ -1,1202 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (ñ) 2012-15 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "stdafx.h" -#pragma hdrstop - -#include "m_hotkeys.h" - -#include "clc.h" -#include "genmenu.h" - -void InitGroupMenus(); - -#define MS_CLIST_HKSTATUS "Clist/HK/SetStatus" - -#define FIRSTCUSTOMMENUITEMID 30000 -#define MENU_CUSTOMITEMMAIN 0x80000000 -//#define MENU_CUSTOMITEMCONTEXT 0x40000000 -//#define MENU_CUSTOMITEMFRAME 0x20000000 - -typedef struct { - WORD id; - int iconId; - TMO_MenuItem mi; -} - CListIntMenuItem, *lpCListIntMenuItem; - -// new menu sys -int hMainMenuObject = 0, hContactMenuObject = 0, hStatusMenuObject = 0; -int UnloadMoveToGroup(void); - -int statustopos(int status); -void Proto_SetStatus(const char *szProto, unsigned status); - -bool prochotkey; - -HANDLE hPreBuildMainMenuEvent, hStatusModeChangeEvent, hPreBuildContactMenuEvent; - -static HMENU hMainMenu, hStatusMenu = 0; -const int statusModeList[MAX_STATUS_COUNT] = -{ - ID_STATUS_OFFLINE, ID_STATUS_ONLINE, ID_STATUS_AWAY, ID_STATUS_NA, ID_STATUS_OCCUPIED, - ID_STATUS_DND, ID_STATUS_FREECHAT, ID_STATUS_INVISIBLE, ID_STATUS_ONTHEPHONE, ID_STATUS_OUTTOLUNCH -}; - -const int skinIconStatusList[MAX_STATUS_COUNT] = -{ - SKINICON_STATUS_OFFLINE, SKINICON_STATUS_ONLINE, SKINICON_STATUS_AWAY, SKINICON_STATUS_NA, SKINICON_STATUS_OCCUPIED, - SKINICON_STATUS_DND, SKINICON_STATUS_FREE4CHAT, SKINICON_STATUS_INVISIBLE, SKINICON_STATUS_ONTHEPHONE, SKINICON_STATUS_OUTTOLUNCH -}; - -static const int statusModePf2List[MAX_STATUS_COUNT] = -{ - 0xFFFFFFFF, PF2_ONLINE, PF2_SHORTAWAY, PF2_LONGAWAY, PF2_LIGHTDND, - PF2_HEAVYDND, PF2_FREECHAT, PF2_INVISIBLE, PF2_ONTHEPHONE, PF2_OUTTOLUNCH -}; - -static INT_PTR statusHotkeys[MAX_STATUS_COUNT]; - -TMO_IntMenuItem **hStatusMainMenuHandles; -int hStatusMainMenuHandlesCnt; - -struct tStatusMenuHandles -{ - int protoindex; - int protostatus[MAX_STATUS_COUNT]; - TMO_IntMenuItem *menuhandle[MAX_STATUS_COUNT]; -}; - -tStatusMenuHandles *hStatusMenuHandles; -int hStatusMenuHandlesCnt; - -struct BuildContactParam -{ - char *szProto; - int isOnList; - int isOnline; -}; - -struct MenuItemData -{ - HMENU OwnerMenu; - int position; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// service functions - -void FreeMenuProtos(void) -{ - if (cli.menuProtos) { - for (int i = 0; i < cli.menuProtoCount; i++) - mir_free(cli.menuProtos[i].szProto); - mir_free(cli.menuProtos); - cli.menuProtos = NULL; - } - cli.menuProtoCount = 0; -} - -////////////////////////////////////////////////////////////////////////// - -int fnGetAverageMode(int *pNetProtoCount) -{ - int netProtoCount = 0, averageMode = 0; - - for (int i = 0; i < accounts.getCount(); i++) { - PROTOACCOUNT *pa = accounts[i]; - if (cli.pfnGetProtocolVisibility(pa->szModuleName) == 0 || Proto_IsAccountLocked(pa)) - continue; - - netProtoCount++; - - if (averageMode == 0) - averageMode = CallProtoServiceInt(NULL, pa->szModuleName, PS_GETSTATUS, 0, 0); - else if (averageMode > 0 && averageMode != CallProtoServiceInt(NULL, pa->szModuleName, PS_GETSTATUS, 0, 0)) { - averageMode = -1; - if (pNetProtoCount == NULL) - break; - } - } - - if (pNetProtoCount) *pNetProtoCount = netProtoCount; - return averageMode; -} - -static int RecursiveDeleteMenu(HMENU hMenu) -{ - int cnt = GetMenuItemCount(hMenu); - for (int i = 0; i < cnt; i++) { - HMENU submenu = GetSubMenu(hMenu, 0); - if (submenu) DestroyMenu(submenu); - DeleteMenu(hMenu, 0, MF_BYPOSITION); - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// MAIN MENU - -struct MainMenuExecParam -{ - char *szServiceName; - TCHAR *szMenuName; - TMO_IntMenuItem *pimi; -}; - -MIR_APP_DLL(HMENU) Menu_BuildMainMenu(void) -{ - NotifyEventHooks(hPreBuildMainMenuEvent, 0, 0); - - Menu_Build(hMainMenu, hMainMenuObject); - DrawMenuBar(cli.hwndContactList); - return hMainMenu; -} - -MIR_APP_DLL(HMENU) Menu_GetMainMenu(void) -{ - RecursiveDeleteMenu(hMainMenu); - return Menu_BuildMainMenu(); -} - -MIR_APP_DLL(HGENMENU) Menu_AddMainMenuItem(TMO_MenuItem *pmi) -{ - MainMenuExecParam *mmep = (MainMenuExecParam*)mir_alloc(sizeof(MainMenuExecParam)); - if (mmep == NULL) - return 0; - - //we need just one parametr. - mmep->szServiceName = mir_strdup(pmi->pszService); - mmep->szMenuName = pmi->name.t; - - TMO_IntMenuItem *pimi = Menu_AddItem(hMainMenuObject, pmi, mmep); - if (pimi == NULL) - return NULL; - - mmep->pimi = pimi; - - const char* name; - bool needFree = false; - - if (pmi->pszService) - name = pmi->pszService; - else if (pmi->flags & CMIF_UNICODE) { - name = mir_t2a(pmi->name.t); - needFree = true; - } - else name = pmi->name.a; - - Menu_ConfigureItem(pimi, MCI_OPT_UNIQUENAME, name); - if (needFree) - mir_free((void*)name); - - return pimi; -} - -// called with: -// wparam - ownerdata -// lparam - lparam from winproc -INT_PTR MainMenuExecService(WPARAM wParam, LPARAM lParam) -{ - MainMenuExecParam *mmep = (MainMenuExecParam*)wParam; - if (mmep != NULL) { - CallService(mmep->szServiceName, mmep->pimi->execParam, lParam); - } - return 1; -} - -INT_PTR FreeOwnerDataMainMenu(WPARAM, LPARAM lParam) -{ - MainMenuExecParam *mmep = (MainMenuExecParam*)lParam; - if (mmep != NULL) { - FreeAndNil((void**)&mmep->szServiceName); - FreeAndNil((void**)&mmep); - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CONTACT MENU - -struct ContactMenuExecParam -{ - char *szServiceName; - char *pszContactOwner; - TMO_IntMenuItem *pimi; -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_APP_DLL(HGENMENU) Menu_AddContactMenuItem(TMO_MenuItem *pmi, const char *pszProto) -{ - // owner data - ContactMenuExecParam *cmep = (ContactMenuExecParam*)mir_calloc(sizeof(ContactMenuExecParam)); - cmep->szServiceName = mir_strdup(pmi->pszService); - if (pszProto != NULL) - cmep->pszContactOwner = mir_strdup(pszProto); - - // may be need to change how UniqueName is formed? - TMO_IntMenuItem *pimi = Menu_AddItem(hContactMenuObject, pmi, cmep); - if (pimi == NULL) - return NULL; - - cmep->pimi = pimi; - - if (pszProto == NULL) - pszProto = ""; - - char buf[256]; - if (pmi->pszService) { - mir_snprintf(buf, "%s/%s", pszProto, (pmi->pszService) ? pmi->pszService : ""); - Menu_ConfigureItem(pimi, MCI_OPT_UNIQUENAME, buf); - } - else if (pmi->name.t) { - if (pmi->flags & CMIF_UNICODE) - mir_snprintf(buf, "%s/NoService/%S", pszProto, pmi->name.t); - else - mir_snprintf(buf, "%s/NoService/%s", pszProto, pmi->name.a); - Menu_ConfigureItem(pimi, MCI_OPT_UNIQUENAME, buf); - } - return pimi; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -EXTERN_C MIR_APP_DLL(HMENU) Menu_BuildContactMenu(MCONTACT hContact) -{ - NotifyEventHooks(hPreBuildContactMenuEvent, hContact, 0); - - char *szProto = GetContactProto(hContact); - - BuildContactParam bcp; - bcp.szProto = szProto; - bcp.isOnList = (db_get_b(hContact, "CList", "NotOnList", 0) == 0); - bcp.isOnline = (szProto != NULL && ID_STATUS_OFFLINE != db_get_w(hContact, szProto, "Status", ID_STATUS_OFFLINE)); - - HMENU hMenu = CreatePopupMenu(); - Menu_Build(hMenu, hContactMenuObject, (WPARAM)&bcp); - return hMenu; -} - -// true - ok, false ignore -static INT_PTR ContactMenuCheckService(WPARAM wParam, LPARAM) -{ - TCheckProcParam *pcpp = (TCheckProcParam*)wParam; - if (pcpp == NULL) - return FALSE; - - BuildContactParam *bcp = (BuildContactParam*)pcpp->wParam; - if (bcp == NULL) - return FALSE; - - ContactMenuExecParam *cmep = (ContactMenuExecParam*)pcpp->MenuItemOwnerData; - if (cmep == NULL) //this is root...build it - return TRUE; - - if (cmep->pszContactOwner != NULL) { - if (bcp->szProto == NULL) return FALSE; - if (mir_strcmp(cmep->pszContactOwner, bcp->szProto)) return FALSE; - } - - TMO_MenuItem &mi = pcpp->MenuItemHandle->mi; - if (mi.flags & CMIF_HIDDEN) return FALSE; - if (mi.flags & CMIF_NOTONLIST && bcp->isOnList) return FALSE; - if (mi.flags & CMIF_NOTOFFLIST && !bcp->isOnList) return FALSE; - if (mi.flags & CMIF_NOTONLINE && bcp->isOnline) return FALSE; - if (mi.flags & CMIF_NOTOFFLINE && !bcp->isOnline) return FALSE; - return TRUE; -} - -// called with: -// wparam - ContactMenuExecParam* -// lparam - lparam from winproc -static INT_PTR ContactMenuExecService(WPARAM wParam, LPARAM lParam) -{ - if (wParam != 0) { - ContactMenuExecParam *cmep = (ContactMenuExecParam*)wParam; - if (cmep->pszContactOwner && cmep->szServiceName && cmep->szServiceName[0] == '/') - ProtoCallService(cmep->pszContactOwner, cmep->szServiceName, lParam, cmep->pimi->execParam); - else - CallService(cmep->szServiceName, lParam, cmep->pimi->execParam); - } - return 0; -} - -// called with: -// lparam - ContactMenuExecParam* -static INT_PTR FreeOwnerDataContactMenu(WPARAM, LPARAM lParam) -{ - ContactMenuExecParam *cmep = (ContactMenuExecParam*)lParam; - if (cmep != NULL) { - FreeAndNil((void**)&cmep->szServiceName); - FreeAndNil((void**)&cmep->pszContactOwner); - FreeAndNil((void**)&cmep); - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// STATUS MENU - -struct StatusMenuExecParam -{ - char *szProto; // This is unique protoname - int protoindex; - int status; - - BOOL custom; - char *svc; - HANDLE hMenuItem; -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_APP_DLL(HGENMENU) Menu_AddStatusMenuItem(TMO_MenuItem *pmi, const char *pszProto) -{ - TMO_IntMenuItem *pRoot = MO_GetIntMenuItem(pmi->root); - - // owner data - StatusMenuExecParam *smep = NULL; - if (pmi->pszService) { - smep = (StatusMenuExecParam*)mir_calloc(sizeof(StatusMenuExecParam)); - smep->custom = TRUE; - smep->svc = mir_strdup(pmi->pszService); - smep->szProto = mir_strdup(pszProto); - } - - TMO_IntMenuItem *pimi = Menu_AddItem(hStatusMenuObject, pmi, smep); - if (pimi == NULL) - return NULL; - - if (smep) - smep->hMenuItem = pimi; - - char buf[MAX_PATH + 64]; - char *p = (pRoot) ? mir_t2a(pRoot->mi.name.t) : NULL; - mir_snprintf(buf, "%s/%s", (p) ? p : "", pmi->pszService ? pmi->pszService : ""); - mir_free(p); - - Menu_ConfigureItem(pimi, MCI_OPT_UNIQUENAME, buf); - return pimi; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_APP_DLL(HMENU) Menu_GetStatusMenu() -{ - RecursiveDeleteMenu(hStatusMenu); - - Menu_Build(hStatusMenu, hStatusMenuObject); - return hStatusMenu; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -BOOL FindMenuHandleByGlobalID(HMENU hMenu, TMO_IntMenuItem *id, MenuItemData* itdat) -{ - if (!itdat) - return FALSE; - - MENUITEMINFO mii = { 0 }; - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_SUBMENU | MIIM_DATA; - for (int i = GetMenuItemCount(hMenu) - 1; i >= 0; i--) { - GetMenuItemInfo(hMenu, i, TRUE, &mii); - if (mii.fType == MFT_SEPARATOR) - continue; - - BOOL inSub = FALSE; - if (mii.hSubMenu) - inSub = FindMenuHandleByGlobalID(mii.hSubMenu, id, itdat); - if (inSub) - return inSub; - - TMO_IntMenuItem *pimi = MO_GetIntMenuItem((HGENMENU)mii.dwItemData); - if (pimi != NULL) { - if (pimi == id) { - itdat->OwnerMenu = hMenu; - itdat->position = i; - return TRUE; - } - } - } - - return FALSE; -} - -INT_PTR StatusMenuCheckService(WPARAM wParam, LPARAM) -{ - TCheckProcParam *pcpp = (TCheckProcParam*)wParam; - if (!pcpp) - return TRUE; - - TMO_IntMenuItem *pimi = MO_GetIntMenuItem(pcpp->MenuItemHandle); - if (!pimi) - return TRUE; - - StatusMenuExecParam *smep = (StatusMenuExecParam*)pcpp->MenuItemOwnerData; - if (smep && !smep->status && smep->custom) { - if (wildcmp(smep->svc, "*XStatus*")) { - int XStatus; - CUSTOM_STATUS cs = { sizeof(cs) }; - cs.flags = CSSF_MASK_STATUS; - cs.status = &XStatus; - if (CallProtoServiceInt(NULL, smep->szProto, PS_GETCUSTOMSTATUSEX, 0, (LPARAM)&cs) != 0) - XStatus = 0; - - char buf[255]; - mir_snprintf(buf, "*XStatus%d", XStatus); - - bool check = wildcmp(smep->svc, buf) != 0; - bool reset = wildcmp(smep->svc, "*XStatus0") != 0; - - if (check) - pimi->mi.flags |= CMIF_CHECKED; - else - pimi->mi.flags &= ~CMIF_CHECKED; - - if (reset || check) { - TMO_IntMenuItem *timiParent = MO_GetIntMenuItem(pimi->mi.root); - if (timiParent) { - LPTSTR ptszName = TranslateTH(pimi->mi.hLangpack, pimi->mi.hIcolibItem ? pimi->mi.name.t : LPGENT("Custom status")); - - timiParent = MO_GetIntMenuItem(pimi->mi.root); - - MenuItemData it = { 0 }; - if (FindMenuHandleByGlobalID(hStatusMenu, timiParent, &it)) { - TCHAR d[100]; - GetMenuString(it.OwnerMenu, it.position, d, _countof(d), MF_BYPOSITION); - - MENUITEMINFO mii = { 0 }; - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_STRING | MIIM_STATE; - if (pimi->iconId != -1) { - mii.fMask |= MIIM_BITMAP; - if (IsWinVerVistaPlus() && IsThemeActive()) { - if (pimi->hBmp == NULL) - pimi->hBmp = ConvertIconToBitmap(NULL, pimi->parent->m_hMenuIcons, pimi->iconId); - mii.hbmpItem = pimi->hBmp; - } - else mii.hbmpItem = HBMMENU_CALLBACK; - } - - mii.fState |= (check && !reset ? MFS_CHECKED : MFS_UNCHECKED); - mii.dwTypeData = ptszName; - SetMenuItemInfo(it.OwnerMenu, it.position, TRUE, &mii); - } - - Menu_ModifyItem(pimi->mi.root, ptszName); - - timiParent->iconId = pimi->iconId; - if (timiParent->hBmp) DeleteObject(timiParent->hBmp); - timiParent->hBmp = NULL; - } - } - } - } - else if (smep && smep->status && !smep->custom) { - int curProtoStatus = (smep->szProto) ? CallProtoServiceInt(NULL, smep->szProto, PS_GETSTATUS, 0, 0) : cli.pfnGetAverageMode(NULL); - if (smep->status == curProtoStatus) - pimi->mi.flags |= CMIF_CHECKED; - else - pimi->mi.flags &= ~CMIF_CHECKED; - } - else if ((!smep || smep->szProto) && pimi->mi.name.a) { - int curProtoStatus = 0; - BOOL IconNeedDestroy = FALSE; - char* prot; - if (smep) - prot = smep->szProto; - else { - char *prn = mir_u2a(pimi->mi.name.t); - prot = NEWSTR_ALLOCA(prn); - if (prn) mir_free(prn); - } - if (Proto_GetAccount(prot) == NULL) - return TRUE; - - if ((curProtoStatus = CallProtoServiceInt(NULL, prot, PS_GETSTATUS, 0, 0)) == CALLSERVICE_NOTFOUND) - curProtoStatus = 0; - - if (curProtoStatus >= ID_STATUS_OFFLINE && curProtoStatus < ID_STATUS_IDLE) - pimi->mi.hIcolibItem = Skin_LoadProtoIcon(prot, curProtoStatus); - else { - pimi->mi.hIcolibItem = (HICON)CallProtoServiceInt(NULL, prot, PS_LOADICON, PLI_PROTOCOL | PLIF_SMALL, 0); - if (pimi->mi.hIcolibItem == (HICON)CALLSERVICE_NOTFOUND) - pimi->mi.hIcolibItem = NULL; - else - IconNeedDestroy = TRUE; - } - - if (pimi->mi.hIcolibItem) { - Menu_ModifyItem(pimi, NULL, pimi->mi.hIcolibItem); - if (IconNeedDestroy) { - DestroyIcon((HICON)pimi->mi.hIcolibItem); - pimi->mi.hIcolibItem = NULL; - } - else IcoLib_ReleaseIcon((HICON)pimi->mi.hIcolibItem); - } - } - - return TRUE; -} - -INT_PTR StatusMenuExecService(WPARAM wParam, LPARAM) -{ - StatusMenuExecParam *smep = (StatusMenuExecParam*)wParam; - if (smep == NULL) - return 0; - - if (smep->custom) { - if (smep->svc && *smep->svc) { - if (smep->szProto && *smep->svc == '/') - ProtoCallService(smep->szProto, smep->svc, 0, (LPARAM)smep->hMenuItem); - else - CallService(smep->svc, 0, (LPARAM)smep->hMenuItem); - } - return 0; - } - - if (smep->status == 0 && smep->protoindex != 0 && smep->szProto != NULL) { - char *prot = smep->szProto; - char szHumanName[64] = { 0 }; - PROTOACCOUNT *acc = Proto_GetAccount(smep->szProto); - bool bIsLocked = !Proto_IsAccountLocked(acc); - db_set_b(NULL, prot, "LockMainStatus", bIsLocked); - - CallProtoServiceInt(NULL, smep->szProto, PS_GETNAME, _countof(szHumanName), (LPARAM)szHumanName); - - TMO_IntMenuItem *pimi = MO_GetIntMenuItem((HGENMENU)smep->protoindex); - if (pimi == NULL) - return 0; - - TMO_IntMenuItem *root = (TMO_IntMenuItem*)pimi->mi.root; - TCHAR buf[256], *ptszName; - if (bIsLocked) { - pimi->mi.flags |= CMIF_CHECKED; - if (cli.bDisplayLocked) { - mir_sntprintf(buf, TranslateT("%s (locked)"), acc->tszAccountName); - ptszName = buf; - } - else ptszName = acc->tszAccountName; - } - else { - ptszName = acc->tszAccountName; - pimi->mi.flags &= ~CMIF_CHECKED; - } - replaceStrT(pimi->mi.name.t, ptszName); - replaceStrT(root->mi.name.t, ptszName); - - if (cli.hwndStatus) - InvalidateRect(cli.hwndStatus, NULL, TRUE); - return 0; - } - - if (smep->szProto != NULL) { - Proto_SetStatus(smep->szProto, smep->status); - NotifyEventHooks(hStatusModeChangeEvent, smep->status, (LPARAM)smep->szProto); - return 0; - } - - int MenusProtoCount = 0; - - for (int i = 0; i < accounts.getCount(); i++) - if (cli.pfnGetProtocolVisibility(accounts[i]->szModuleName)) - MenusProtoCount++; - - cli.currentDesiredStatusMode = smep->status; - - for (int j = 0; j < accounts.getCount(); j++) { - PROTOACCOUNT *pa = accounts[j]; - if (!Proto_IsAccountEnabled(pa)) - continue; - if (MenusProtoCount > 1 && Proto_IsAccountLocked(pa)) - continue; - - Proto_SetStatus(pa->szModuleName, cli.currentDesiredStatusMode); - } - NotifyEventHooks(hStatusModeChangeEvent, cli.currentDesiredStatusMode, 0); - db_set_w(NULL, "CList", "Status", (WORD)cli.currentDesiredStatusMode); - return 1; -} - -INT_PTR FreeOwnerDataStatusMenu(WPARAM, LPARAM lParam) -{ - StatusMenuExecParam *smep = (StatusMenuExecParam*)lParam; - if (smep != NULL) { - mir_free(smep->szProto); - mir_free(smep->svc); - mir_free(smep); - } - - return (0); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Other menu functions - -INT_PTR MenuProcessCommand(WPARAM wParam, LPARAM lParam) -{ - WORD cmd = LOWORD(wParam); - - if (HIWORD(wParam) & MPCF_MAINMENU) { - int hst = LOWORD(wParam); - if (hst >= ID_STATUS_OFFLINE && hst <= ID_STATUS_OUTTOLUNCH) { - int pos = statustopos(hst); - if (pos != -1 && hStatusMainMenuHandles != NULL) - return Menu_ProcessCommand(hStatusMainMenuHandles[pos], lParam); - } - } - - if (!(cmd >= CLISTMENUIDMIN && cmd <= CLISTMENUIDMAX)) - return 0; // DO NOT process ids outside from clist menu id range v0.7.0.27+ - - //process old menu sys - if (HIWORD(wParam) & MPCF_CONTACTMENU) - return MO_ProcessCommandBySubMenuIdent((int)hContactMenuObject, LOWORD(wParam), lParam); - - //unknown old menu - return Menu_ProcessCommandById(LOWORD(wParam), lParam); -} - -BOOL FindMenuHanleByGlobalID(HMENU hMenu, TMO_IntMenuItem *id, MenuItemData* itdat) -{ - if (!itdat) - return FALSE; - - BOOL inSub = FALSE; - - MENUITEMINFO mii = { 0 }; - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_SUBMENU | MIIM_DATA; - for (int i = GetMenuItemCount(hMenu) - 1; i >= 0; i--) { - GetMenuItemInfo(hMenu, i, TRUE, &mii); - if (mii.fType == MFT_SEPARATOR) - continue; - - if (mii.hSubMenu) - inSub = FindMenuHanleByGlobalID(mii.hSubMenu, id, itdat); - if (inSub) - return inSub; - - TMO_IntMenuItem *pimi = MO_GetIntMenuItem((HGENMENU)mii.dwItemData); - if (pimi != NULL) { - if (pimi == id) { - itdat->OwnerMenu = hMenu; - itdat->position = i; - return TRUE; - } - } - } - - return FALSE; -} - -static INT_PTR MenuProcessHotkey(WPARAM vKey, LPARAM) -{ - prochotkey = true; - - bool res = - Menu_ProcessHotKey(hStatusMenuObject, vKey) || - Menu_ProcessHotKey(hMainMenuObject, vKey); - - prochotkey = false; - - return res; -} - -static int MenuIconsChanged(WPARAM, LPARAM) -{ - //just rebuild menu - RebuildMenuOrder(); - cli.pfnCluiProtocolStatusChanged(0, 0); - return 0; -} - -static INT_PTR SetStatusMode(WPARAM wParam, LPARAM) -{ - prochotkey = true; - MenuProcessCommand(MAKEWPARAM(LOWORD(wParam), MPCF_MAINMENU), 0); - prochotkey = false; - return 0; -} - -int fnGetProtocolVisibility(const char *accName) -{ - if (accName) { - PROTOACCOUNT *pa = Proto_GetAccount(accName); - if (pa && pa->bIsVisible && Proto_IsAccountEnabled(pa) && pa->ppro) { - PROTOCOLDESCRIPTOR *pd = Proto_IsProtocolLoaded(pa->szProtoName); - if (pd == NULL || pd->type != PROTOTYPE_PROTOCOL) - return FALSE; - - return (pa->ppro->GetCaps(PFLAGNUM_2, 0) & ~pa->ppro->GetCaps(PFLAGNUM_5, 0)); - } - } - - return FALSE; -} - -int fnGetProtoIndexByPos(PROTOCOLDESCRIPTOR **proto, int protoCnt, int Pos) -{ - char buf[10]; - _itoa(Pos, buf, 10); - - DBVARIANT dbv; - if (!db_get_s(NULL, "Protocols", buf, &dbv)) { - for (int p = 0; p < protoCnt; p++) { - if (mir_strcmp(proto[p]->szName, dbv.pszVal) == 0) { - db_free(&dbv); - return p; - } - } - - db_free(&dbv); - } - - return -1; -} - -int fnGetAccountIndexByPos(int Pos) -{ - for (int i = 0; i < accounts.getCount(); i++) - if (accounts[i]->iOrder == Pos) - return i; - - return -1; -} - -void RebuildMenuOrder(void) -{ - BYTE bHideStatusMenu = db_get_b(NULL, "CLUI", "DontHideStatusMenu", 0); // cool perversion, though - - //clear statusmenu - RecursiveDeleteMenu(hStatusMenu); - - //status menu - if (hStatusMenuObject != 0) { - Menu_RemoveObject(hStatusMenuObject); - mir_free(hStatusMainMenuHandles); - mir_free(hStatusMenuHandles); - } - - hStatusMenuObject = Menu_AddObject("StatusMenu", LPGEN("Status menu"), "StatusMenuCheckService", "StatusMenuExecService"); - Menu_ConfigureObject(hStatusMenuObject, MCO_OPT_FREE_SERVICE, (INT_PTR)"CLISTMENUS/FreeOwnerDataStatusMenu"); - - hStatusMainMenuHandles = (TMO_IntMenuItem**)mir_calloc(_countof(statusModeList) * sizeof(TMO_IntMenuItem*)); - hStatusMainMenuHandlesCnt = _countof(statusModeList); - - hStatusMenuHandles = (tStatusMenuHandles*)mir_calloc(sizeof(tStatusMenuHandles)*accounts.getCount()); - hStatusMenuHandlesCnt = accounts.getCount(); - - FreeMenuProtos(); - - for (int s = 0; s < accounts.getCount(); s++) { - int i = cli.pfnGetAccountIndexByPos(s); - if (i == -1) - continue; - - PROTOACCOUNT *pa = accounts[i]; - int pos = 0; - if (!bHideStatusMenu && !cli.pfnGetProtocolVisibility(pa->szModuleName)) - continue; - - DWORD flags = pa->ppro->GetCaps(PFLAGNUM_2, 0) & ~pa->ppro->GetCaps(PFLAGNUM_5, 0); - HICON ic; - TCHAR tbuf[256]; - - // adding root - CMenuItem mi; - mi.flags = CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; - mi.position = pos++; - mi.hIcon = ic = (HICON)CallProtoServiceInt(NULL, pa->szModuleName, PS_LOADICON, PLI_PROTOCOL | PLIF_SMALL, 0); - - if (Proto_IsAccountLocked(pa) && cli.bDisplayLocked) { - mir_sntprintf(tbuf, _countof(tbuf), TranslateT("%s (locked)"), pa->tszAccountName); - mi.name.t = tbuf; - } - else mi.name.t = pa->tszAccountName; - - // owner data - StatusMenuExecParam *smep = (StatusMenuExecParam*)mir_calloc(sizeof(StatusMenuExecParam)); - smep->szProto = mir_strdup(pa->szModuleName); - TMO_IntMenuItem *rootmenu = Menu_AddItem(hStatusMenuObject, &mi, smep); - - memset(&mi, 0, sizeof(mi)); - mi.flags = CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; - mi.root = rootmenu; - mi.position = pos++; - mi.hIcon = ic; - - // owner data - smep = (StatusMenuExecParam*)mir_calloc(sizeof(StatusMenuExecParam)); - smep->szProto = mir_strdup(pa->szModuleName); - - if (Proto_IsAccountLocked(pa)) - mi.flags |= CMIF_CHECKED; - - if ((mi.flags & CMIF_CHECKED) && cli.bDisplayLocked) { - mir_sntprintf(tbuf, _countof(tbuf), TranslateT("%s (locked)"), pa->tszAccountName); - mi.name.t = tbuf; - } - else mi.name.t = pa->tszAccountName; - - TMO_IntMenuItem *pimi = Menu_AddItem(hStatusMenuObject, &mi, smep); - smep->protoindex = (int)pimi; - Menu_ModifyItem(pimi, mi.name.t, mi.hIcon, mi.flags); - - cli.menuProtos = (MenuProto*)mir_realloc(cli.menuProtos, sizeof(MenuProto)*(cli.menuProtoCount + 1)); - memset(&(cli.menuProtos[cli.menuProtoCount]), 0, sizeof(MenuProto)); - cli.menuProtos[cli.menuProtoCount].pMenu = rootmenu; - cli.menuProtos[cli.menuProtoCount].szProto = mir_strdup(pa->szModuleName); - - cli.menuProtoCount++; - - char buf[256]; - mir_snprintf(buf, "RootProtocolIcon_%s", pa->szModuleName); - Menu_ConfigureItem(pimi, MCI_OPT_UNIQUENAME, buf); - - DestroyIcon(ic); - pos += 500000; - - for (int j = 0; j < _countof(statusModeList); j++) { - if (!(flags & statusModePf2List[j])) - continue; - - // adding - memset(&mi, 0, sizeof(mi)); - mi.flags = CMIF_TCHAR; - if (statusModeList[j] == ID_STATUS_OFFLINE) - mi.flags |= CMIF_CHECKED; - mi.root = rootmenu; - mi.position = pos++; - mi.name.t = cli.pfnGetStatusModeDescription(statusModeList[j], GSMDF_UNTRANSLATED); - mi.hIcon = Skin_LoadProtoIcon(pa->szModuleName, statusModeList[j]); - - // owner data - StatusMenuExecParam *smep = (StatusMenuExecParam*)mir_calloc(sizeof(StatusMenuExecParam)); - smep->custom = FALSE; - smep->status = statusModeList[j]; - smep->protoindex = i; - smep->szProto = mir_strdup(pa->szModuleName); - - hStatusMenuHandles[i].protoindex = i; - hStatusMenuHandles[i].protostatus[j] = statusModeList[j]; - hStatusMenuHandles[i].menuhandle[j] = Menu_AddItem(hStatusMenuObject, &mi, smep); - - char buf[256]; - mir_snprintf(buf, "ProtocolIcon_%s_%s", pa->szModuleName, mi.name.a); - Menu_ConfigureItem(hStatusMenuHandles[i].menuhandle[j], MCI_OPT_UNIQUENAME, buf); - - IcoLib_ReleaseIcon(mi.hIcon); - } - } - - NotifyEventHooks(cli.hPreBuildStatusMenuEvent, 0, 0); - int pos = 200000; - - // add to root menu - for (int j = 0; j < _countof(statusModeList); j++) { - for (int i = 0; i < accounts.getCount(); i++) { - PROTOACCOUNT *pa = accounts[i]; - if (!bHideStatusMenu && !cli.pfnGetProtocolVisibility(pa->szModuleName)) - continue; - - DWORD flags = pa->ppro->GetCaps(PFLAGNUM_2, 0) & ~pa->ppro->GetCaps(PFLAGNUM_5, 0); - if (!(flags & statusModePf2List[j])) - continue; - - CMenuItem mi; - mi.flags = CMIF_TCHAR; - if (statusModeList[j] == ID_STATUS_OFFLINE) - mi.flags |= CMIF_CHECKED; - - mi.hIcon = Skin_LoadIcon(skinIconStatusList[j]); - mi.position = pos++; - - // owner data - StatusMenuExecParam *smep = (StatusMenuExecParam*)mir_calloc(sizeof(StatusMenuExecParam)); - smep->status = statusModeList[j]; - { - TCHAR buf[256], hotkeyName[100]; - WORD hotKey = GetHotkeyValue(statusHotkeys[j]); - HotkeyToName(hotkeyName, _countof(hotkeyName), HIBYTE(hotKey), LOBYTE(hotKey)); - mir_sntprintf(buf, _T("%s\t%s"), cli.pfnGetStatusModeDescription(statusModeList[j], 0), hotkeyName); - mi.name.t = buf; - hStatusMainMenuHandles[j] = Menu_AddItem(hStatusMenuObject, &mi, smep); - - hStatusMainMenuHandles[j]->hotKey = hotKey; - } - - char buf[256]; - mir_snprintf(buf, "Root2ProtocolIcon_%s_%s", pa->szModuleName, mi.name.a); - Menu_ConfigureItem(hStatusMainMenuHandles[j], MCI_OPT_UNIQUENAME, buf); - - IcoLib_ReleaseIcon(mi.hIcon); - break; - } - } - - Menu_GetStatusMenu(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static int sttRebuildHotkeys(WPARAM, LPARAM) -{ - for (int j = 0; j < _countof(statusModeList); j++) { - TCHAR buf[256], hotkeyName[100]; - WORD hotKey = GetHotkeyValue(statusHotkeys[j]); - HotkeyToName(hotkeyName, _countof(hotkeyName), HIBYTE(hotKey), LOBYTE(hotKey)); - mir_sntprintf(buf, _T("%s\t%s"), cli.pfnGetStatusModeDescription(statusModeList[j], 0), hotkeyName); - Menu_ModifyItem(hStatusMainMenuHandles[j], buf); - - hStatusMainMenuHandles[j]->hotKey = MAKELONG(HIBYTE(hotKey), LOBYTE(hotKey)); - } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -int statustopos(int status) -{ - for (int j = 0; j < _countof(statusModeList); j++) - if (status == statusModeList[j]) - return j; - - return -1; -} - -static int MenuProtoAck(WPARAM, LPARAM lParam) -{ - ACKDATA *ack = (ACKDATA*)lParam; - if (ack->type != ACKTYPE_STATUS) return 0; - if (ack->result != ACKRESULT_SUCCESS) return 0; - if (hStatusMainMenuHandles == NULL) return 0; - if (cli.pfnGetProtocolVisibility(ack->szModule) == 0) return 0; - - int overallStatus = cli.pfnGetAverageMode(NULL); - - if (overallStatus >= ID_STATUS_OFFLINE) { - int pos = statustopos(cli.currentStatusMenuItem); - if (pos == -1) - pos = 0; - - // reset all current possible checked statuses - for (int pos2 = 0; pos2 < hStatusMainMenuHandlesCnt; pos2++) - if (pos2 >= 0 && pos2 < hStatusMainMenuHandlesCnt) - Menu_ModifyItem(hStatusMainMenuHandles[pos2], NULL, INVALID_HANDLE_VALUE, 0); - - cli.currentStatusMenuItem = overallStatus; - pos = statustopos(cli.currentStatusMenuItem); - if (pos >= 0 && pos < hStatusMainMenuHandlesCnt) - Menu_SetChecked(hStatusMainMenuHandles[pos], true); - } - else { - int pos = statustopos(cli.currentStatusMenuItem); - if (pos == -1) - pos = 0; - - if (pos >= 0 && pos < hStatusMainMenuHandlesCnt) - Menu_ModifyItem(hStatusMainMenuHandles[pos], NULL, INVALID_HANDLE_VALUE, 0); - - cli.currentStatusMenuItem = 0; - } - - for (int i = 0; i < accounts.getCount(); i++) { - if (!mir_strcmp(accounts[i]->szModuleName, ack->szModule)) { - if (((int)ack->hProcess >= ID_STATUS_OFFLINE || (int)ack->hProcess == 0) && (int)ack->hProcess < ID_STATUS_OFFLINE + _countof(statusModeList)) { - int pos = statustopos((int)ack->hProcess); - if (pos == -1) - pos = 0; - for (pos = 0; pos < _countof(statusModeList); pos++) - Menu_ModifyItem(hStatusMenuHandles[i].menuhandle[pos], NULL, INVALID_HANDLE_VALUE, 0); - } - - if (ack->lParam >= ID_STATUS_OFFLINE && ack->lParam < ID_STATUS_OFFLINE + _countof(statusModeList)) { - int pos = statustopos((int)ack->lParam); - if (pos >= 0 && pos < _countof(statusModeList)) - Menu_SetChecked(hStatusMenuHandles[i].menuhandle[pos], true); - } - break; - } - } - - //BuildStatusMenu(0, 0); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static MenuProto* FindProtocolMenu(const char *proto) -{ - for (int i = 0; i < cli.menuProtoCount; i++) - if (cli.menuProtos[i].pMenu && !mir_strcmpi(cli.menuProtos[i].szProto, proto)) - return &cli.menuProtos[i]; - - if (cli.menuProtoCount == 1) - if (!mir_strcmpi(cli.menuProtos[0].szProto, proto)) - return &cli.menuProtos[0]; - - return NULL; -} - -HGENMENU fnGetProtocolMenu(const char* proto) -{ - MenuProto *mp = FindProtocolMenu(proto); - return (mp) ? mp->pMenu : NULL; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static INT_PTR HotkeySetStatus(WPARAM, LPARAM lParam) -{ - return SetStatusMode(lParam, 0); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// PROTOCOL MENU - -MIR_APP_DLL(HGENMENU) Menu_AddProtoMenuItem(TMO_MenuItem *mi, const char *pszProto) -{ - if (mi == NULL) - return NULL; - - if (db_get_b(NULL, "CList", "MoveProtoMenus", TRUE)) - return Menu_AddStatusMenuItem(mi, pszProto); - - char szService[100]; - if (pszProto && mi->pszService && *mi->pszService == '/') { - strncpy_s(szService, pszProto, _TRUNCATE); - strncat_s(szService, mi->pszService, _TRUNCATE); - mi->pszService = szService; - } - return Menu_AddMainMenuItem(mi); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void InitCustomMenus(void) -{ - CreateServiceFunction("MainMenuExecService", MainMenuExecService); - - CreateServiceFunction("ContactMenuExecService", ContactMenuExecService); - CreateServiceFunction("ContactMenuCheckService", ContactMenuCheckService); - - CreateServiceFunction("StatusMenuExecService", StatusMenuExecService); - CreateServiceFunction("StatusMenuCheckService", StatusMenuCheckService); - - // free services - CreateServiceFunction("CLISTMENUS/FreeOwnerDataMainMenu", FreeOwnerDataMainMenu); - CreateServiceFunction("CLISTMENUS/FreeOwnerDataContactMenu", FreeOwnerDataContactMenu); - CreateServiceFunction("CLISTMENUS/FreeOwnerDataStatusMenu", FreeOwnerDataStatusMenu); - - CreateServiceFunction(MS_CLIST_SETSTATUSMODE, SetStatusMode); - - CreateServiceFunction(MS_CLIST_MENUPROCESSCOMMAND, MenuProcessCommand); - CreateServiceFunction(MS_CLIST_MENUPROCESSHOTKEY, MenuProcessHotkey); - - hPreBuildContactMenuEvent = CreateHookableEvent(ME_CLIST_PREBUILDCONTACTMENU); - hPreBuildMainMenuEvent = CreateHookableEvent(ME_CLIST_PREBUILDMAINMENU); - cli.hPreBuildStatusMenuEvent = CreateHookableEvent(ME_CLIST_PREBUILDSTATUSMENU); - hStatusModeChangeEvent = CreateHookableEvent(ME_CLIST_STATUSMODECHANGE); - - HookEvent(ME_PROTO_ACK, MenuProtoAck); - - hMainMenu = CreatePopupMenu(); - hStatusMenu = CreatePopupMenu(); - - hStatusMainMenuHandles = NULL; - hStatusMainMenuHandlesCnt = 0; - - hStatusMenuHandles = NULL; - hStatusMenuHandlesCnt = 0; - - // new menu sys - InitGenMenu(); - - // main menu - hMainMenuObject = Menu_AddObject("MainMenu", LPGEN("Main menu"), 0, "MainMenuExecService"); - Menu_ConfigureObject(hMainMenuObject, MCO_OPT_USERDEFINEDITEMS, TRUE); - Menu_ConfigureObject(hMainMenuObject, MCO_OPT_FREE_SERVICE, (INT_PTR)"CLISTMENUS/FreeOwnerDataMainMenu"); - - // contact menu - hContactMenuObject = Menu_AddObject("ContactMenu", LPGEN("Contact menu"), "ContactMenuCheckService", "ContactMenuExecService"); - Menu_ConfigureObject(hContactMenuObject, MCO_OPT_USERDEFINEDITEMS, TRUE); - Menu_ConfigureObject(hContactMenuObject, MCO_OPT_FREE_SERVICE, (INT_PTR)"CLISTMENUS/FreeOwnerDataContactMenu"); - - // other menus - InitGroupMenus(); - - // initialize hotkeys - CreateServiceFunction(MS_CLIST_HKSTATUS, HotkeySetStatus); - - HOTKEYDESC hkd = { sizeof(hkd) }; - hkd.ptszSection = _T("Status"); - hkd.dwFlags = HKD_TCHAR; - for (int i = 0; i < _countof(statusHotkeys); i++) { - char szName[30]; - mir_snprintf(szName, _countof(szName), "StatusHotKey_%d", i); - hkd.pszName = szName; - hkd.lParam = statusModeList[i]; - hkd.ptszDescription = fnGetStatusModeDescription(hkd.lParam, 0); - hkd.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL, '0' + i) | HKF_MIRANDA_LOCAL; - hkd.pszService = MS_CLIST_HKSTATUS; - statusHotkeys[i] = Hotkey_Register(&hkd); - } - - HookEvent(ME_HOTKEYS_CHANGED, sttRebuildHotkeys); - - // add exit command to menu - CMenuItem mi; - mi.position = 0x7fffffff; - mi.pszService = "CloseAction"; - mi.name.a = LPGEN("E&xit"); - mi.hIcolibItem = Skin_GetIconHandle(SKINICON_OTHER_EXIT); - Menu_AddMainMenuItem(&mi); - - cli.currentStatusMenuItem = ID_STATUS_OFFLINE; - cli.currentDesiredStatusMode = ID_STATUS_OFFLINE; - - HookEvent(ME_SKIN_ICONSCHANGED, MenuIconsChanged); -} - -void UninitCustomMenus(void) -{ - mir_free(hStatusMainMenuHandles); - hStatusMainMenuHandles = NULL; - - mir_free(hStatusMenuHandles); - hStatusMenuHandles = NULL; - - Menu_RemoveObject(hMainMenuObject); - Menu_RemoveObject(hMainMenuObject); - - UnloadMoveToGroup(); - FreeMenuProtos(); - - DestroyMenu(hMainMenu); - DestroyMenu(hStatusMenu); -} diff --git a/src/mir_app/src/clistmod.cpp b/src/mir_app/src/clistmod.cpp index 7ce932340c..0054d57c26 100644 --- a/src/mir_app/src/clistmod.cpp +++ b/src/mir_app/src/clistmod.cpp @@ -26,7 +26,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "clc.h" INT_PTR ContactChangeGroup(WPARAM wParam, LPARAM lParam); -int InitFramesMenus(void); int InitCListEvents(void); void UninitCListEvents(void); int ContactSettingChanged(WPARAM wParam, LPARAM lParam); @@ -488,7 +487,6 @@ int LoadContactListModule2(void) InitCListEvents(); InitGroupServices(); - InitFramesMenus(); cli.pfnInitTray(); hCListImages = ImageList_Create(16, 16, ILC_MASK | ILC_COLOR32, 13, 0); diff --git a/src/mir_app/src/framesmenu.cpp b/src/mir_app/src/framesmenu.cpp deleted file mode 100644 index 4d904620df..0000000000 --- a/src/mir_app/src/framesmenu.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (ñ) 2012-15 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "stdafx.h" - -#include -#include "genmenu.h" - -static int hFrameMenuObject; -static HANDLE hPreBuildFrameMenuEvent; - -// contactmenu exec param(ownerdata) -// also used in checkservice -struct FrameMenuExecParam -{ - ptrA szServiceName; -}; - -INT_PTR FreeOwnerDataFrameMenu(WPARAM, LPARAM lParam) -{ - delete (FrameMenuExecParam*)lParam; - return 0; -} - -static INT_PTR AddContextFrameMenuItem(WPARAM, LPARAM lParam) -{ - TMO_MenuItem *pmi = (TMO_MenuItem*)lParam; - - FrameMenuExecParam *fmep = new FrameMenuExecParam(); - fmep->szServiceName = mir_strdup(pmi->pszService); - return (INT_PTR)Menu_AddItem(hFrameMenuObject, pmi, fmep); -} - -// called with: -// wparam - ownerdata -// lparam - lparam from winproc -INT_PTR FrameMenuExecService(WPARAM wParam, LPARAM lParam) -{ - FrameMenuExecParam *fmep = (FrameMenuExecParam*)wParam; - if (fmep == NULL) - return -1; - - CallService(fmep->szServiceName, lParam, 0); - return 0; -} - -// true - ok,false ignore -INT_PTR FrameMenuCheckService(WPARAM wParam, LPARAM) -{ - TCheckProcParam *pcpp = (TCheckProcParam*)wParam; - if (pcpp == NULL) - return FALSE; - - TMO_IntMenuItem *pimi = pcpp->MenuItemHandle; - return pimi->execParam == pcpp->wParam || pimi->execParam == -1; -} - -static INT_PTR ContextFrameMenuNotify(WPARAM wParam, LPARAM lParam) -{ - NotifyEventHooks(hPreBuildFrameMenuEvent, wParam, lParam); - return 0; -} - -static INT_PTR BuildContextFrameMenu(WPARAM wParam, LPARAM lParam) -{ - ContextFrameMenuNotify(wParam, -1); - - HMENU hMenu = CreatePopupMenu(); - Menu_Build(hMenu, hFrameMenuObject, wParam, lParam); - return (INT_PTR)hMenu; -} - -//========================== Frames end - -int InitFramesMenus(void) -{ - CreateServiceFunction("FrameMenuExecService", FrameMenuExecService); - CreateServiceFunction("FrameMenuCheckService", FrameMenuCheckService); - CreateServiceFunction("FrameMenuFreeService", FreeOwnerDataFrameMenu); - - CreateServiceFunction("CList/AddContextFrameMenuItem", AddContextFrameMenuItem); - CreateServiceFunction(MS_CLIST_MENUBUILDFRAMECONTEXT, BuildContextFrameMenu); - CreateServiceFunction(MS_CLIST_FRAMEMENUNOTIFY, ContextFrameMenuNotify); - hPreBuildFrameMenuEvent = CreateHookableEvent(ME_CLIST_PREBUILDFRAMEMENU); - - // frame menu object - hFrameMenuObject = Menu_AddObject("FrameMenu", LPGEN("Frame menu"), "FrameMenuCheckService", "FrameMenuExecService"); - Menu_ConfigureObject(hFrameMenuObject, MCO_OPT_FREE_SERVICE, "FrameMenuFreeService"); - return 0; -} diff --git a/src/mir_app/src/genmenu.cpp b/src/mir_app/src/genmenu.cpp deleted file mode 100644 index 758d3c8b5e..0000000000 --- a/src/mir_app/src/genmenu.cpp +++ /dev/null @@ -1,1199 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (ñ) 2012-15 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "stdafx.h" -#include "genmenu.h" - -static bool bIsGenMenuInited; -bool bIconsDisabled; -static mir_cs csMenuHook; - -static int NextObjectId = 0x100, NextObjectMenuItemId = CLISTMENUIDMIN; - -#if defined(_DEBUG) -static void DumpMenuItem(TMO_IntMenuItem* pParent, int level = 0) -{ - char temp[ 30 ]; - memset(temp, '\t', level); - temp[ level ] = 0; - - for (TMO_IntMenuItem *pimi = pParent; pimi != NULL; pimi = pimi->next) { - Netlib_Logf(NULL, "%sMenu item %08p [%08p]: %S", temp, pimi, pimi->mi.root, pimi->mi.name.t); - - TMO_IntMenuItem *submenu = pimi->submenu.first; - if (submenu) - DumpMenuItem(submenu, level+1); - } -} - -#endif - -static int CompareMenus(const TIntMenuObject* p1, const TIntMenuObject* p2) -{ - return mir_strcmp(p1->pszName, p2->pszName); -} - -LIST g_menus(10, NumericKeySortT); - -void FreeAndNil(void **p) -{ - if (p == NULL) - return; - - if (*p != NULL) { - mir_free(*p); - *p = NULL; - } -} - -TIntMenuObject* GetMenuObjbyId(int id) -{ - switch (id) { - case MO_MAIN: id = hMainMenuObject; break; - case MO_CONTACT: id = hContactMenuObject; break; - case MO_STATUS: id = hStatusMenuObject; break; - case MO_PROTO: - if (db_get_b(NULL, "CList", "MoveProtoMenus", true)) - id = hStatusMenuObject; - else - id = hMainMenuObject; - } - - return g_menus.find((TIntMenuObject*)&id); -} - -LPTSTR GetMenuItemText(TMO_IntMenuItem *pimi) -{ - if (pimi->mi.flags & CMIF_KEEPUNTRANSLATED) - return pimi->mi.name.t; - - return TranslateTH(pimi->mi.hLangpack, pimi->mi.name.t); -} - -/////////////////////////////////////////////////////////////////////////////// - -TMO_IntMenuItem* MO_RecursiveWalkMenu(TMO_IntMenuItem *parent, pfnWalkFunc func, void* param) -{ - if (parent == NULL) - return FALSE; - - TMO_IntMenuItem *pnext; - for (TMO_IntMenuItem *pimi = parent; pimi != NULL; pimi = pnext) { - TMO_IntMenuItem *submenu = pimi->submenu.first; - pnext = pimi->next; - if (func(pimi, param)) // it can destroy the menu item - return pimi; - - if (submenu) { - TMO_IntMenuItem *res = MO_RecursiveWalkMenu(submenu, func, param); - if (res) - return res; - } - } - - return FALSE; -} - -/////////////////////////////////////////////////////////////////////////////// - -MIR_APP_DLL(BOOL) Menu_MeasureItem(MEASUREITEMSTRUCT *mis) -{ - if (!bIsGenMenuInited) - return FALSE; - - if (mis == NULL) - return FALSE; - - // prevent win9x from ugly menus displaying when there is no icon - mis->itemWidth = 0; - mis->itemHeight = 0; - - TMO_IntMenuItem *pimi = MO_GetIntMenuItem((HGENMENU)mis->itemData); - if (pimi == NULL) - return FALSE; - - if (pimi->iconId == -1) - return FALSE; - - mis->itemWidth = max(0, g_iIconSX - GetSystemMetrics(SM_CXMENUCHECK) + 4); - mis->itemHeight = g_iIconSY + 2; - return TRUE; -} - -/////////////////////////////////////////////////////////////////////////////// - -MIR_APP_DLL(BOOL) Menu_DrawItem(DRAWITEMSTRUCT *dis) -{ - if (!bIsGenMenuInited) - return FALSE; - - if (dis == NULL) - return FALSE; - - mir_cslock lck(csMenuHook); - - TMO_IntMenuItem *pimi = MO_GetIntMenuItem((HGENMENU)dis->itemData); - if (pimi == NULL || pimi->iconId == -1) - return FALSE; - - int y = (dis->rcItem.bottom - dis->rcItem.top - g_iIconSY) / 2 + 1; - if (dis->itemState & ODS_SELECTED) { - if (dis->itemState & ODS_CHECKED) { - RECT rc; - rc.left = 2; rc.right = g_iIconSX + 2; - rc.top = y; rc.bottom = rc.top + g_iIconSY + 2; - FillRect(dis->hDC, &rc, GetSysColorBrush(COLOR_HIGHLIGHT)); - ImageList_DrawEx(pimi->parent->m_hMenuIcons, pimi->iconId, dis->hDC, 2, y, 0, 0, CLR_NONE, CLR_DEFAULT, ILD_SELECTED); - } - else ImageList_DrawEx(pimi->parent->m_hMenuIcons, pimi->iconId, dis->hDC, 2, y, 0, 0, CLR_NONE, CLR_DEFAULT, ILD_FOCUS); - } - else { - if (dis->itemState & ODS_CHECKED) { - RECT rc; - rc.left = 0; rc.right = g_iIconSX + 4; - rc.top = y - 2; rc.bottom = rc.top + g_iIconSY + 4; - DrawEdge(dis->hDC, &rc, BDR_SUNKENOUTER, BF_RECT); - InflateRect(&rc, -1, -1); - COLORREF menuCol = GetSysColor(COLOR_MENU); - COLORREF hiliteCol = GetSysColor(COLOR_3DHIGHLIGHT); - HBRUSH hBrush = CreateSolidBrush(RGB((GetRValue(menuCol) + GetRValue(hiliteCol)) / 2, (GetGValue(menuCol) + GetGValue(hiliteCol)) / 2, (GetBValue(menuCol) + GetBValue(hiliteCol)) / 2)); - FillRect(dis->hDC, &rc, GetSysColorBrush(COLOR_MENU)); - DeleteObject(hBrush); - ImageList_DrawEx(pimi->parent->m_hMenuIcons, pimi->iconId, dis->hDC, 2, y, 0, 0, CLR_NONE, GetSysColor(COLOR_MENU), ILD_BLEND50); - } - else ImageList_DrawEx(pimi->parent->m_hMenuIcons, pimi->iconId, dis->hDC, 2, y, 0, 0, CLR_NONE, CLR_NONE, ILD_NORMAL); - } - return TRUE; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -int MO_RemoveAllObjects() -{ - for (int i = 0; i < g_menus.getCount(); i++) - delete g_menus[i]; - g_menus.destroy(); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -EXTERN_C MIR_APP_DLL(BOOL) Menu_ProcessHotKey(int hMenuObject, int key) -{ - if (!bIsGenMenuInited) - return -1; - - mir_cslock lck(csMenuHook); - TIntMenuObject *pmo = GetMenuObjbyId(hMenuObject); - if (pmo == NULL) - return FALSE; - - for (TMO_IntMenuItem *pimi = pmo->m_items.first; pimi != NULL; pimi = pimi->next) { - if (pimi->hotKey == 0) continue; - if (HIWORD(pimi->hotKey) != key) continue; - if (!(LOWORD(pimi->hotKey) & MOD_ALT) != !(GetKeyState(VK_MENU) & 0x8000)) continue; - if (!(LOWORD(pimi->hotKey) & MOD_CONTROL) != !(GetKeyState(VK_CONTROL) & 0x8000)) continue; - if (!(LOWORD(pimi->hotKey) & MOD_SHIFT) != !(GetKeyState(VK_SHIFT) & 0x8000)) continue; - - Menu_ProcessCommand(pimi, 0); - return TRUE; - } - - return FALSE; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_APP_DLL(HGENMENU) Menu_GetProtocolRoot(PROTO_INTERFACE *pThis) -{ - if (pThis == NULL) - return 0; - - if (db_get_b(NULL, "CList", "MoveProtoMenus", TRUE)) { - if (pThis->m_hMainMenuItem != NULL) { - Menu_RemoveItem(pThis->m_hMainMenuItem); - pThis->m_hMainMenuItem = NULL; - } - return cli.pfnGetProtocolMenu(pThis->m_szModuleName); - } - - TIntMenuObject *pmo = GetMenuObjbyId(hMainMenuObject); - if (pmo == NULL) - return NULL; - - mir_cslock lck(csMenuHook); - for (TMO_IntMenuItem *p = pmo->m_items.first; p != NULL; p = p->next) - if (!mir_strcmp(p->UniqName, pThis->m_szModuleName)) - return p; - - // create protocol root in the main menu - CMenuItem mi; - mi.name.t = pThis->m_tszUserName; - mi.position = 500090000; - mi.flags = CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; - mi.hIcolibItem = pThis->m_hProtoIcon; - return pThis->m_hMainMenuItem = Menu_AddMainMenuItem(&mi); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_APP_DLL(int) Menu_GetItemInfo(HGENMENU hMenuItem, TMO_MenuItem &pInfo) -{ - if (!bIsGenMenuInited) - return -1; - - TMO_IntMenuItem *pimi = MO_GetIntMenuItem(hMenuItem); - mir_cslock lck(csMenuHook); - if (pimi == NULL) - return -1; - - pInfo = pimi->mi; - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static int FindDefaultItem(TMO_IntMenuItem *pimi, void*) -{ - if (pimi->mi.flags & (CMIF_GRAYED | CMIF_HIDDEN)) - return FALSE; - - return (pimi->mi.flags & CMIF_DEFAULT) ? TRUE : FALSE; -} - -MIR_APP_DLL(HGENMENU) Menu_GetDefaultItem(HGENMENU hMenu) -{ - if (!bIsGenMenuInited) - return NULL; - - TMO_IntMenuItem *pimi = MO_GetIntMenuItem(hMenu); - mir_cslock lck(csMenuHook); - return (pimi) ? MO_RecursiveWalkMenu(pimi, FindDefaultItem, NULL) : NULL; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static void Menu_SetItemFlags(HGENMENU hMenuItem, bool bSet, int mask) -{ - TMO_IntMenuItem *pimi = MO_GetIntMenuItem(hMenuItem); - if (pimi == NULL) - return; - - int flags = pimi->mi.flags; - if (bSet) - flags |= mask; - else - flags &= ~mask; - - // we allow to set only first 3 bits - mir_cslock lck(csMenuHook); - pimi->mi.flags = flags | (pimi->mi.flags & 0xFFFFFFF8); -} - -MIR_APP_DLL(void) Menu_EnableItem(HGENMENU hMenuItem, bool bEnable) -{ - Menu_SetItemFlags(hMenuItem, !bEnable, CMIF_GRAYED); -} - -MIR_APP_DLL(void) Menu_ShowItem(HGENMENU hMenuItem, bool bShow) -{ - Menu_SetItemFlags(hMenuItem, !bShow, CMIF_HIDDEN); -} - -MIR_APP_DLL(void) Menu_SetChecked(HGENMENU hMenuItem, bool bSet) -{ - Menu_SetItemFlags(hMenuItem, bSet, CMIF_CHECKED); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_APP_DLL(int) Menu_ModifyItem(HGENMENU hMenuItem, const TCHAR *ptszName, HANDLE hIcon, int iFlags) -{ - if (!bIsGenMenuInited) - return -1; - - mir_cslock lck(csMenuHook); - - TMO_IntMenuItem *pimi = MO_GetIntMenuItem(hMenuItem); - if (pimi == NULL) - return -1; - - if (ptszName != NULL) - replaceStrT(pimi->mi.name.t, ptszName); - - if (iFlags != -1) { - // we allow to set only first 3 bits - int oldflags = (pimi->mi.flags & 0xFFFFFFF8); - pimi->mi.flags = (iFlags & 0x07) | oldflags; - } - - if (hIcon != INVALID_HANDLE_VALUE && !bIconsDisabled) { - HANDLE hIcolibItem = IcoLib_IsManaged((HICON)hIcon); - if (hIcolibItem) { - HICON hIcon = IcoLib_GetIconByHandle(hIcolibItem, false); - if (hIcon != NULL) { - pimi->hIcolibItem = hIcolibItem; - pimi->iconId = ImageList_ReplaceIcon(pimi->parent->m_hMenuIcons, pimi->iconId, hIcon); - IcoLib_ReleaseIcon(hIcon); - } - else pimi->iconId = -1, pimi->hIcolibItem = NULL; - } - else { - pimi->mi.hIcolibItem = (HICON)hIcon; - if (hIcon != NULL) - pimi->iconId = ImageList_ReplaceIcon(pimi->parent->m_hMenuIcons, pimi->iconId, (HICON)hIcon); - else - pimi->iconId = -1; //fixme, should remove old icon & shuffle all iconIds - } - if (pimi->hBmp) { - DeleteObject(pimi->hBmp); - pimi->hBmp = NULL; - } - } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_APP_DLL(void*) Menu_GetItemData(HGENMENU hMenuItem) -{ - if (!bIsGenMenuInited) - return NULL; - - mir_cslock lck(csMenuHook); - TMO_IntMenuItem *pimi = MO_GetIntMenuItem(hMenuItem); - return (pimi) ? pimi->pUserData : NULL; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -TMO_IntMenuItem *MO_GetIntMenuItem(HGENMENU wParam) -{ - TMO_IntMenuItem *result = (TMO_IntMenuItem*)wParam; - if (result == NULL) - return NULL; - - __try { - if (result->signature != MENUITEM_SIGNATURE) - result = NULL; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - result = NULL; - } - - return result; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static int FindMenuByCommand(TMO_IntMenuItem *pimi, void* pCommand) -{ - return (pimi->iCommand == (int)pCommand); -} - -int MO_ProcessCommandBySubMenuIdent(int menuID, int command, LPARAM lParam) -{ - if (!bIsGenMenuInited) - return -1; - - TMO_IntMenuItem *pimi; - { - mir_cslock lck(csMenuHook); - TIntMenuObject *pmo = GetMenuObjbyId(menuID); - if (pmo == NULL) - return -1; - - pimi = MO_RecursiveWalkMenu(pmo->m_items.first, FindMenuByCommand, (void*)command); - } - - return (pimi) ? Menu_ProcessCommand(pimi, lParam) : -1; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_APP_DLL(BOOL) Menu_ProcessCommandById(int command, LPARAM lParam) -{ - if (!bIsGenMenuInited) - return -1; - - mir_cslock lck(csMenuHook); - for (int i = 0; i < g_menus.getCount(); i++) - if (TMO_IntMenuItem *pimi = MO_RecursiveWalkMenu(g_menus[i]->m_items.first, FindMenuByCommand, (void*)command)) - return Menu_ProcessCommand(pimi, lParam); - - return false; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_APP_DLL(BOOL) Menu_ProcessCommand(HGENMENU hMenuItem, LPARAM lParam) -{ - if (!bIsGenMenuInited) - return false; - - TMO_IntMenuItem *pimi; - { - mir_cslock lck(csMenuHook); - if ((pimi = MO_GetIntMenuItem(hMenuItem)) == NULL) - return false; - } - - LPCSTR srvname = pimi->parent->ExecService; - CallService(srvname, (WPARAM)pimi->pUserData, lParam); - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_APP_DLL(int) Menu_ConfigureItem(HGENMENU hItem, int iOption, INT_PTR value) -{ - if (!bIsGenMenuInited) - return -1; - - mir_cslock lck(csMenuHook); - TMO_IntMenuItem *pimi = MO_GetIntMenuItem(hItem); - if (pimi == NULL) - return -1; - - switch (iOption) { - case MCI_OPT_UNIQUENAME: - replaceStr(pimi->UniqName, (char*)value); - return 0; - - case MCI_OPT_HOTKEY: - pimi->hotKey = (DWORD)value; - return 0; - - case MCI_OPT_EXECPARAM: - pimi->execParam = value; - return 0; - } - - return 1; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_APP_DLL(int) Menu_ConfigureObject(int hMenuObject, int setting, INT_PTR value) -{ - if (!bIsGenMenuInited) - return false; - - mir_cslock lck(csMenuHook); - TIntMenuObject *pmo = GetMenuObjbyId(hMenuObject); - if (pmo != NULL) { - switch (setting) { - case MCO_OPT_ONADD_SERVICE: - replaceStr(pmo->onAddService, (char*)value); - return true; - - case MCO_OPT_FREE_SERVICE: - replaceStr(pmo->FreeService, (char*)value); - return true; - - case MCO_OPT_CHECK_SERVICE: - replaceStr(pmo->CheckService, (char*)value); - return true; - - case MCO_OPT_USERDEFINEDITEMS: - pmo->m_bUseUserDefinedItems = (BOOL)value; - return true; - } - } - - return false; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_APP_DLL(int) Menu_AddObject(LPCSTR szName, LPCSTR szDisplayName, LPCSTR szCheckService, LPCSTR szExecService) -{ - if (szName == NULL || szDisplayName == NULL) - return NULL; - - mir_cslock lck(csMenuHook); - - TIntMenuObject *p = new TIntMenuObject(); - p->id = NextObjectId++; - p->pszName = mir_strdup(szName); - p->ptszDisplayName = mir_a2t(szDisplayName); - p->CheckService = mir_strdup(szCheckService); - p->ExecService = mir_strdup(szExecService); - p->m_hMenuIcons = ImageList_Create(g_iIconSX, g_iIconSY, ILC_COLOR32 | ILC_MASK, 15, 100); - g_menus.insert(p); - return p->id; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_APP_DLL(int) Menu_RemoveObject(int hMenuObject) -{ - if (!bIsGenMenuInited || hMenuObject == 0) - return -1; - - mir_cslock lck(csMenuHook); - TIntMenuObject *pmo = GetMenuObjbyId(hMenuObject); - if (pmo == NULL) - return -1; - - g_menus.remove(pmo); - delete pmo; - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// wparam = MenuItemHandle -// lparam = 0 - -static int FreeMenuItem(TMO_IntMenuItem* pimi, void*) -{ - pimi->parent->freeItem(pimi); - return FALSE; -} - -static int FindParent(TMO_IntMenuItem* pimi, void* p) -{ - return pimi->next == p; -} - -MIR_APP_DLL(int) Menu_RemoveItem(HGENMENU hMenuItem) -{ - mir_cslock lck(csMenuHook); - TMO_IntMenuItem *pimi = MO_GetIntMenuItem(hMenuItem); - if (pimi == NULL) - return -1; - - if (pimi->submenu.first) { - MO_RecursiveWalkMenu(pimi->submenu.first, FreeMenuItem, NULL); - pimi->submenu.first = NULL; - } - - TMO_IntMenuItem *prev = MO_RecursiveWalkMenu(pimi->owner->first, FindParent, pimi); - if (prev) - prev->next = pimi->next; - if (pimi->owner->first == pimi) - pimi->owner->first = pimi->next; - if (pimi->owner->last == pimi) - pimi->owner->last = prev; - - pimi->signature = 0; // invalidate all future calls to that object - pimi->parent->freeItem(pimi); - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// - -struct KillMenuItemsParam -{ - KillMenuItemsParam(int _hLangpack) : - hLangpack(_hLangpack), - arItems(10) - {} - - int hLangpack; - LIST arItems; -}; - -int KillMenuItems(TMO_IntMenuItem *pimi, KillMenuItemsParam* param) -{ - if (pimi->mi.hLangpack == param->hLangpack) - param->arItems.insert(pimi); - return FALSE; -} - -MIR_APP_DLL(void) KillModuleMenus(int hLangpack) -{ - if (!bIsGenMenuInited) - return; - - KillMenuItemsParam param(hLangpack); - - mir_cslock lck(csMenuHook); - for (int i = 0; i < g_menus.getCount(); i++) - MO_RecursiveWalkMenu(g_menus[i]->m_items.first, (pfnWalkFunc)KillMenuItems, ¶m); - - for (int k = 0; k < param.arItems.getCount(); k++) - Menu_RemoveItem(param.arItems[k]); -} - -/////////////////////////////////////////////////////////////////////////////// -// we presume that this function is being called inside csMenuHook only - -static int PackMenuItems(TMO_IntMenuItem *pimi, void*) -{ - pimi->iCommand = NextObjectMenuItemId++; - return FALSE; -} - -static int GetNextObjectMenuItemId() -{ - // if menu commands are exausted, pack the menu array - if (NextObjectMenuItemId >= CLISTMENUIDMAX) { - NextObjectMenuItemId = CLISTMENUIDMIN; - for (int i = 0; i < g_menus.getCount(); i++) - MO_RecursiveWalkMenu(g_menus[i]->m_items.first, PackMenuItems, NULL); - } - - return NextObjectMenuItemId++; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Adds new submenu -// Returns a handle to the newly created root item or NULL - -static int FindRoot(TMO_IntMenuItem *pimi, void *param) -{ - if (pimi->mi.name.t != NULL) - if (pimi->submenu.first && !mir_tstrcmp(pimi->mi.name.t, (TCHAR*)param)) - return TRUE; - - return FALSE; -} - -MIR_APP_DLL(HGENMENU) Menu_CreateRoot(int hMenuObject, LPCTSTR ptszName, int position, HANDLE hIcoLib, int hLang) -{ - mir_cslock lck(csMenuHook); - TIntMenuObject *pmo = GetMenuObjbyId(hMenuObject); - if (pmo == NULL) - return NULL; - - TMO_IntMenuItem *oldroot = MO_RecursiveWalkMenu(pmo->m_items.first, FindRoot, (void*)ptszName); - if (oldroot != NULL) - return oldroot; - - CMenuItem mi; - mi.flags = CMIF_TCHAR; - mi.hIcolibItem = hIcoLib; - mi.hLangpack = hLang; - mi.name.t = (TCHAR*)ptszName; - mi.position = position; - return Menu_AddItem(hMenuObject, &mi, NULL); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Adds new menu item -// Returns a handle to the newly created item or NULL - -MIR_APP_DLL(HGENMENU) Menu_AddItem(int hMenuObject, TMO_MenuItem *pmi, void *pUserData) -{ - if (!bIsGenMenuInited || pmi == NULL) - return NULL; - - mir_cslock lck(csMenuHook); - TIntMenuObject *pmo = GetMenuObjbyId(hMenuObject); - if (pmo == NULL) - return NULL; - - TMO_IntMenuItem* p = (TMO_IntMenuItem*)mir_calloc(sizeof(TMO_IntMenuItem)); - p->parent = pmo; - p->signature = MENUITEM_SIGNATURE; - p->iCommand = GetNextObjectMenuItemId(); - p->mi = *pmi; - p->iconId = -1; - p->OverrideShow = TRUE; - p->originalPosition = pmi->position; - p->pUserData = pUserData; - - if (pmi->flags & CMIF_UNICODE) - p->mi.name.t = mir_tstrdup(pmi->name.t); - else - p->mi.name.t = mir_a2u(pmi->name.a); - - if (pmi->hIcon != NULL && !bIconsDisabled) { - HANDLE hIcolibItem = IcoLib_IsManaged(pmi->hIcon); - if (hIcolibItem != NULL) { - HICON hIcon = IcoLib_GetIconByHandle(hIcolibItem, false); - p->iconId = ImageList_AddIcon(pmo->m_hMenuIcons, hIcon); - p->hIcolibItem = hIcolibItem; - IcoLib_ReleaseIcon(hIcon); - } - else p->iconId = ImageList_AddIcon(pmo->m_hMenuIcons, pmi->hIcon); - } - - TMO_IntMenuItem *pRoot = (p->mi.root != NULL) ? MO_GetIntMenuItem(p->mi.root) : NULL; - if (pRoot) { - p->owner = &pRoot->submenu; - - if (pRoot->iconId == -1) - pRoot->iconId = p->iconId; - } - else p->owner = &pmo->m_items; - - if (!p->owner->first) - p->owner->first = p; - if (p->owner->last) - p->owner->last->next = p; - p->owner->last = p; - return p; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// wparam = MenuObjectHandle -// lparam = PMO_MenuItem - -static int WhereToPlace(HMENU hMenu, TMO_MenuItem *mi) -{ - MENUITEMINFO mii = { 0 }; - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_SUBMENU | MIIM_DATA; - for (int i = GetMenuItemCount(hMenu) - 1; i >= 0; i--) { - GetMenuItemInfo(hMenu, i, TRUE, &mii); - if (mii.fType != MFT_SEPARATOR) { - TMO_IntMenuItem *pimi = MO_GetIntMenuItem((HGENMENU)mii.dwItemData); - if (pimi != NULL) - if (pimi->mi.position <= mi->position) - return i + 1; - } - } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static DWORD GetMenuItemType(HMENU hMenu, int uItem) -{ - MENUITEMINFO mii = { 0 }; - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_TYPE; - GetMenuItemInfo(hMenu, uItem, TRUE, &mii); - return mii.fType; -} - -static UINT GetMenuItemTypeData(HMENU hMenu, int uItem, TMO_IntMenuItem* &p) -{ - MENUITEMINFO mii = { 0 }; - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_DATA | MIIM_TYPE; - GetMenuItemInfo(hMenu, uItem, TRUE, &mii); - p = MO_GetIntMenuItem((HGENMENU)mii.dwItemData); - return mii.fType; -} - -static void InsertSeparator(HMENU hMenu, int uItem) -{ - MENUITEMINFO mii = { 0 }; - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_TYPE; - mii.fType = MFT_SEPARATOR; - InsertMenuItem(hMenu, uItem, TRUE, &mii); -} - -static void InsertMenuItemWithSeparators(HMENU hMenu, int uItem, MENUITEMINFO *lpmii) -{ - TMO_IntMenuItem *pimi = MO_GetIntMenuItem((HGENMENU)lpmii->dwItemData), *p; - if (pimi == NULL) - return; - - // check for separator before - if (uItem) { - UINT fType = GetMenuItemTypeData(hMenu, uItem - 1, p); - if (p != NULL && fType != MFT_SEPARATOR) { - if ((p->mi.position / SEPARATORPOSITIONINTERVAL) != (pimi->mi.position / SEPARATORPOSITIONINTERVAL)) { - // but might be supposed to be after the next one instead - if (!(uItem < GetMenuItemCount(hMenu) && GetMenuItemType(hMenu, uItem) == MFT_SEPARATOR)) - InsertSeparator(hMenu, uItem); - uItem++; - } - } - } - - // check for separator after - if (uItem < GetMenuItemCount(hMenu)) { - UINT fType = GetMenuItemTypeData(hMenu, uItem, p); - if (p != NULL && fType != MFT_SEPARATOR) - if ((p->mi.position / SEPARATORPOSITIONINTERVAL) != (pimi->mi.position / SEPARATORPOSITIONINTERVAL)) - InsertSeparator(hMenu, uItem); - } - - // create local copy *lpmii so we can change some flags - MENUITEMINFO mii = *lpmii; - - int count = GetMenuItemCount(hMenu); - if (count != 0 && (count % 33) == 0 && pimi->mi.root != NULL) { - if (!(mii.fMask & MIIM_FTYPE)) - mii.fType = 0; - mii.fMask |= MIIM_FTYPE; - mii.fType |= MFT_MENUBARBREAK; - } - - if (!pimi->CustomName) - mii.dwTypeData = GetMenuItemText(pimi); - - InsertMenuItem(hMenu, uItem, TRUE, &mii); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#ifdef _DEBUG -#define PUTPOSITIONSONMENU -#endif - -void GetMenuItemName(TMO_IntMenuItem *pMenuItem, char* pszDest, size_t cbDestSize) -{ - if (pMenuItem->UniqName) - mir_snprintf(pszDest, cbDestSize, "{%s}", pMenuItem->UniqName); - else if (pMenuItem->mi.flags & CMIF_UNICODE) - mir_snprintf(pszDest, cbDestSize, "{%s}", (char*)_T2A(pMenuItem->mi.name.t)); - else - mir_snprintf(pszDest, cbDestSize, "{%s}", pMenuItem->mi.name.t); -} - -static HMENU BuildRecursiveMenu(HMENU hMenu, TMO_IntMenuItem *pRootMenu, INT_PTR iRootLevel, WPARAM wParam, LPARAM lParam) -{ - if (pRootMenu == NULL) - return NULL; - - TIntMenuObject *pmo = pRootMenu->parent; - - if (iRootLevel == 0) - while (GetMenuItemCount(hMenu) > 0) - DeleteMenu(hMenu, 0, MF_BYPOSITION); - - for (TMO_IntMenuItem *pmi = pRootMenu; pmi != NULL; pmi = pmi->next) { - TMO_MenuItem *mi = &pmi->mi; - if (mi->flags & CMIF_HIDDEN) - continue; - - if (pmo->CheckService != NULL) { - TCheckProcParam CheckParam; - CheckParam.wParam = wParam; - CheckParam.lParam = lParam; - CheckParam.MenuItemOwnerData = pmi->pUserData; - CheckParam.MenuItemHandle = pmi; - if (CallService(pmo->CheckService, (WPARAM)&CheckParam, 0) == FALSE) - continue; - } - - /**************************************/ - if (iRootLevel == 0 && mi->root == NULL && pmo->m_bUseUserDefinedItems) { - char DBString[256]; - DBVARIANT dbv = { 0 }; - int pos; - char MenuNameItems[256]; - mir_snprintf(MenuNameItems, _countof(MenuNameItems), "%s_Items", pmo->pszName); - - char menuItemName[256]; - GetMenuItemName(pmi, menuItemName, sizeof(menuItemName)); - - // check if it visible - mir_snprintf(DBString, _countof(DBString), "%s_visible", menuItemName); - if (db_get_b(NULL, MenuNameItems, DBString, -1) == -1) - db_set_b(NULL, MenuNameItems, DBString, 1); - - pmi->OverrideShow = TRUE; - if (!db_get_b(NULL, MenuNameItems, DBString, 1)) { - pmi->OverrideShow = FALSE; - continue; // find out what value to return if not getting added - } - - // mi.name.t - mir_snprintf(DBString, _countof(DBString), "%s_name", menuItemName); - if (!db_get_ts(NULL, MenuNameItems, DBString, &dbv)) { - if (mir_tstrlen(dbv.ptszVal) > 0) - replaceStrT(pmi->CustomName, dbv.ptszVal); - db_free(&dbv); - } - - mir_snprintf(DBString, _countof(DBString), "%s_pos", menuItemName); - if ((pos = db_get_dw(NULL, MenuNameItems, DBString, -1)) == -1) { - db_set_dw(NULL, MenuNameItems, DBString, mi->position); - if (pmi->submenu.first) - mi->position = 0; - } - else mi->position = pos; - } - - /**************************************/ - - if (iRootLevel != (INT_PTR)pmi->mi.root) - continue; - - int i = WhereToPlace(hMenu, mi); - - MENUITEMINFO mii = { 0 }; - mii.cbSize = sizeof(mii); - mii.dwItemData = (LPARAM)pmi; - mii.fMask = MIIM_DATA | MIIM_ID | MIIM_STRING; - if (pmi->iconId != -1) { - mii.fMask |= MIIM_BITMAP; - if (IsWinVerVistaPlus() && IsThemeActive()) { - if (pmi->hBmp == NULL) - pmi->hBmp = ConvertIconToBitmap(NULL, pmi->parent->m_hMenuIcons, pmi->iconId); - mii.hbmpItem = pmi->hBmp; - } - else mii.hbmpItem = HBMMENU_CALLBACK; - } - - mii.fMask |= MIIM_STATE; - mii.fState = ((pmi->mi.flags & CMIF_GRAYED) ? MFS_GRAYED : MFS_ENABLED); - mii.fState |= ((pmi->mi.flags & CMIF_CHECKED) ? MFS_CHECKED : MFS_UNCHECKED); - if (pmi->mi.flags & CMIF_DEFAULT) - mii.fState |= MFS_DEFAULT; - - mii.dwTypeData = (pmi->CustomName) ? pmi->CustomName : mi->name.t; - - // it's a submenu - if (pmi->submenu.first) { - mii.fMask |= MIIM_SUBMENU; - mii.hSubMenu = CreatePopupMenu(); - -#ifdef PUTPOSITIONSONMENU - if (GetKeyState(VK_CONTROL) & 0x8000) { - TCHAR str[256]; - mir_sntprintf(str, _countof(str), _T("%s (%d, id %x)"), mi->name.a, mi->position, mii.dwItemData); - mii.dwTypeData = str; - } -#endif - - InsertMenuItemWithSeparators(hMenu, i, &mii); - BuildRecursiveMenu(mii.hSubMenu, pmi->submenu.first, LPARAM(pmi), wParam, lParam); - } - else { - mii.wID = pmi->iCommand; - -#ifdef PUTPOSITIONSONMENU - if (GetKeyState(VK_CONTROL) & 0x8000) { - TCHAR str[256]; - mir_sntprintf(str, _countof(str), _T("%s (%d, id %x)"), mi->name.a, mi->position, mii.dwItemData); - mii.dwTypeData = str; - } -#endif - - if (pmo->onAddService != NULL) - if (CallService(pmo->onAddService, (WPARAM)&mii, (LPARAM)pmi) == FALSE) - continue; - - InsertMenuItemWithSeparators(hMenu, i, &mii); - } - } - - return hMenu; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// wparam started hMenu -// lparam ListParam* -// result hMenu - -EXTERN_C MIR_APP_DLL(HMENU) Menu_Build(HMENU parent, int hMenuObject, WPARAM wParam, LPARAM lParam) -{ - if (!bIsGenMenuInited) - return NULL; - - mir_cslock lck(csMenuHook); - - TIntMenuObject *pmo = GetMenuObjbyId(hMenuObject); - if (pmo == NULL) - return NULL; - - #if defined(_DEBUG) - // DumpMenuItem(pmo->m_items.first); - #endif - - return BuildRecursiveMenu(parent, pmo->m_items.first, 0, wParam, lParam); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// iconlib in menu - -static int MO_ReloadIcon(TMO_IntMenuItem *pmi, void*) -{ - if (pmi->hIcolibItem) { - HICON newIcon = IcoLib_GetIconByHandle(pmi->hIcolibItem, false); - if (newIcon) - ImageList_ReplaceIcon(pmi->parent->m_hMenuIcons, pmi->iconId, newIcon); - - IcoLib_ReleaseIcon(newIcon); - } - - return FALSE; -} - -int OnIconLibChanges(WPARAM, LPARAM) -{ - { - mir_cslock lck(csMenuHook); - for (int mo = 0; mo < g_menus.getCount(); mo++) - if (hStatusMenuObject != g_menus[mo]->id) //skip status menu - MO_RecursiveWalkMenu(g_menus[mo]->m_items.first, MO_ReloadIcon, 0); - } - - cli.pfnReloadProtoMenus(); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static int MO_RegisterIcon(TMO_IntMenuItem *pmi, void*) -{ - TCHAR *uname = (pmi->UniqName) ? mir_a2t(pmi->UniqName) : mir_tstrdup(pmi->CustomName), - *descr = GetMenuItemText(pmi); - - if (!uname && !descr) - return FALSE; - - if (!pmi->hIcolibItem) { - HICON hIcon = ImageList_GetIcon(pmi->parent->m_hMenuIcons, pmi->iconId, 0); - - TCHAR sectionName[256]; - mir_sntprintf(sectionName, _countof(sectionName), LPGENT("Menu icons") _T("/%s"), TranslateTS(pmi->parent->ptszDisplayName)); - - char iconame[256]; - mir_snprintf(iconame, _countof(iconame), "genmenu_%s_%s", pmi->parent->pszName, uname && *uname ? uname : descr); - - // remove '&' - if (descr) { - descr = NEWTSTR_ALLOCA(descr); - - for (TCHAR *p = descr; *p; p++) { - if ((p = _tcschr(p, '&')) == NULL) - break; - - memmove(p, p + 1, sizeof(TCHAR)*(mir_tstrlen(p + 1) + 1)); - if (*p == '\0') - p++; - } - } - - SKINICONDESC sid = { 0 }; - sid.flags = SIDF_TCHAR; - sid.section.t = sectionName; - sid.pszName = iconame; - sid.description.t = descr; - sid.hDefaultIcon = hIcon; - pmi->hIcolibItem = IcoLib_AddIcon(&sid, 0); - - Safe_DestroyIcon(hIcon); - if (hIcon = IcoLib_GetIcon(iconame)) { - ImageList_ReplaceIcon(pmi->parent->m_hMenuIcons, pmi->iconId, hIcon); - IcoLib_ReleaseIcon(hIcon); - } - } - - mir_free(uname); - return FALSE; -} - -int RegisterAllIconsInIconLib() -{ - // register all icons - for (int mo = 0; mo < g_menus.getCount(); mo++) { - if (hStatusMenuObject == g_menus[mo]->id) //skip status menu - continue; - - MO_RecursiveWalkMenu(g_menus[mo]->m_items.first, MO_RegisterIcon, 0); - } - - return 0; -} - -int TryProcessDoubleClick(MCONTACT hContact) -{ - TIntMenuObject *pmo = GetMenuObjbyId(hContactMenuObject); - if (pmo != NULL) { - NotifyEventHooks(hPreBuildContactMenuEvent, hContact, 0); - - TMO_IntMenuItem *pimi = Menu_GetDefaultItem(pmo->m_items.first); - if (pimi != NULL) { - Menu_ProcessCommand(pimi, hContact); - return 0; - } - } - - return 1; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Static services - -int posttimerid; - -static VOID CALLBACK PostRegisterIcons(HWND, UINT, UINT_PTR, DWORD) -{ - KillTimer(0, posttimerid); - RegisterAllIconsInIconLib(); -} - -static int OnModulesLoaded(WPARAM, LPARAM) -{ - posttimerid = SetTimer(NULL, 0, 5, (TIMERPROC)PostRegisterIcons); - HookEvent(ME_SKIN2_ICONSCHANGED, OnIconLibChanges); - return 0; -} - -int InitGenMenu() -{ - bIconsDisabled = db_get_b(NULL, "CList", "DisableMenuIcons", 0) != 0; - bIsGenMenuInited = true; - - HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded); - HookEvent(ME_OPT_INITIALISE, GenMenuOptInit); - return 0; -} - -int UnitGenMenu() -{ - if (bIsGenMenuInited) { - mir_cslock lck(csMenuHook); - MO_RemoveAllObjects(); - bIsGenMenuInited = false; - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -TIntMenuObject::TIntMenuObject() -{ -} - -TIntMenuObject::~TIntMenuObject() -{ - MO_RecursiveWalkMenu(m_items.first, FreeMenuItem, NULL); - - FreeAndNil((void**)&FreeService); - FreeAndNil((void**)&onAddService); - FreeAndNil((void**)&CheckService); - FreeAndNil((void**)&ExecService); - FreeAndNil((void**)&ptszDisplayName); - FreeAndNil((void**)&pszName); - - ImageList_Destroy(m_hMenuIcons); -} - -void TIntMenuObject::freeItem(TMO_IntMenuItem *p) -{ - if (FreeService) - CallService(FreeService, (WPARAM)p, (LPARAM)p->pUserData); - - p->signature = 0; - FreeAndNil((void**)&p->mi.name.t); - FreeAndNil((void**)&p->UniqName); - FreeAndNil((void**)&p->CustomName); - if (p->hBmp) DeleteObject(p->hBmp); - mir_free(p); -} diff --git a/src/mir_app/src/genmenuopt.cpp b/src/mir_app/src/genmenuopt.cpp deleted file mode 100644 index 6e57e67f9d..0000000000 --- a/src/mir_app/src/genmenuopt.cpp +++ /dev/null @@ -1,501 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (ñ) 2012-15 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "stdafx.h" -#include "genmenu.h" - -#define STR_SEPARATOR _T("-----------------------------------") - -extern bool bIconsDisabled; -extern int DefaultImageListColorDepth; -void RebuildProtoMenus(); - -///////////////////////////////////////////////////////////////////////////////////////// - -struct MenuItemOptData : public MZeroedObject -{ - ~MenuItemOptData() {} - - int pos; - - ptrT name; - ptrT defname; - ptrA uniqname; - - bool bShow; - int id; - - TMO_IntMenuItem *pimi; -}; - -static int SortMenuItems(const MenuItemOptData *p1, const MenuItemOptData *p2) -{ - if (p1->pos < p2->pos) return -1; - if (p1->pos > p2->pos) return 1; - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -class CGenMenuOptionsPage : public CDlgBase -{ - int iInitMenuValue; - bool bRebuild; - - void SaveTree() - { - int MenuObjectId; - if (!GetCurrentMenuObjectID(MenuObjectId)) - return; - - TCHAR idstr[100]; - - TVITEMEX tvi; - tvi.hItem = m_menuItems.GetRoot(); - tvi.cchTextMax = _countof(idstr); - tvi.mask = TVIF_TEXT | TVIF_PARAM | TVIF_HANDLE | TVIF_IMAGE; - tvi.pszText = idstr; - - int count = 0; - TIntMenuObject *pmo = GetMenuObjbyId(MenuObjectId); - if (pmo == NULL) - return; - - char MenuNameItems[256]; - mir_snprintf(MenuNameItems, _countof(MenuNameItems), "%s_Items", pmo->pszName); - int runtimepos = 100; - - while (tvi.hItem != NULL) { - m_menuItems.GetItem(&tvi); - MenuItemOptData *iod = (MenuItemOptData*)tvi.lParam; - if (iod->pimi) { - char menuItemName[256], DBString[300]; - GetMenuItemName(iod->pimi, menuItemName, sizeof(menuItemName)); - - mir_snprintf(DBString, _countof(DBString), "%s_visible", menuItemName); - db_set_b(NULL, MenuNameItems, DBString, tvi.iImage != 0); - - mir_snprintf(DBString, _countof(DBString), "%s_pos", menuItemName); - db_set_dw(NULL, MenuNameItems, DBString, runtimepos); - - mir_snprintf(DBString, _countof(DBString), "%s_name", menuItemName); - if (iod->name != NULL && iod->defname != NULL && - mir_tstrcmp(iod->name, iod->defname) != 0) - db_set_ts(NULL, MenuNameItems, DBString, iod->name); - else - db_unset(NULL, MenuNameItems, DBString); - - runtimepos += 100; - } - - if (iod->name && !mir_tstrcmp(iod->name, STR_SEPARATOR) && tvi.iImage) - runtimepos += SEPARATORPOSITIONINTERVAL; - - tvi.hItem = m_menuItems.GetNextSibling(tvi.hItem); - count++; - } - } - - void FreeTreeData() - { - HTREEITEM hItem = m_menuItems.GetRoot(); - while (hItem != NULL) { - TVITEMEX tvi; - tvi.mask = TVIF_HANDLE | TVIF_PARAM; - tvi.hItem = hItem; - m_menuItems.GetItem(&tvi); - delete (MenuItemOptData *)tvi.lParam; - - tvi.lParam = 0; - m_menuItems.SetItem(&tvi); - - hItem = m_menuItems.GetNextSibling(hItem); - } - } - - void RebuildCurrent() - { - int MenuObjectID; - if (GetCurrentMenuObjectID(MenuObjectID)) - BuildTree(MenuObjectID, true); - } - - void BuildTreeInternal(const char *pszModule, bool bReread, HGENMENU pFirst, HTREEITEM hRoot) - { - LIST arItems(10, SortMenuItems); - - for (TMO_IntMenuItem *p = pFirst; p != NULL; p = p->next) { - // filter out items whose presence & position might not be changed - if (p->mi.flags & CMIF_SYSTEM) - continue; - - char menuItemName[256]; - GetMenuItemName(p, menuItemName, _countof(menuItemName)); - - MenuItemOptData *PD = new MenuItemOptData(); - - char buf[256]; - mir_snprintf(buf, "%s_name", menuItemName); - ptrT tszName(db_get_tsa(NULL, pszModule, buf)); - if (tszName != 0) - PD->name = tszName.detach(); - else - PD->name = mir_tstrdup(GetMenuItemText(p)); - - PD->pimi = p; - PD->defname = mir_tstrdup(GetMenuItemText(p)); - - mir_snprintf(buf, "%s_visible", menuItemName); - PD->bShow = db_get_b(NULL, pszModule, buf, 1) != 0; - - if (bReread) { - mir_snprintf(buf, "%s_pos", menuItemName); - PD->pos = db_get_dw(NULL, pszModule, buf, 1); - } - else PD->pos = (PD->pimi) ? PD->pimi->originalPosition : 0; - - PD->id = p->iCommand; - - if (p->UniqName) - PD->uniqname = mir_strdup(p->UniqName); - - arItems.insert(PD); - } - - int lastpos = 0; - bool bIsFirst = TRUE; - - TVINSERTSTRUCT tvis; - tvis.hParent = hRoot; - tvis.hInsertAfter = TVI_LAST; - tvis.item.mask = TVIF_PARAM | TVIF_CHILDREN | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE; - - for (int i = 0; i < arItems.getCount(); i++) { - MenuItemOptData *PD = arItems[i]; - if (PD->pos - lastpos >= SEPARATORPOSITIONINTERVAL) { - MenuItemOptData *sep = new MenuItemOptData(); - sep->id = -1; - sep->name = mir_tstrdup(STR_SEPARATOR); - sep->pos = PD->pos - 1; - - tvis.item.lParam = (LPARAM)sep; - tvis.item.pszText = sep->name; - tvis.item.iImage = tvis.item.iSelectedImage = 1; - tvis.item.cChildren = 0; - m_menuItems.InsertItem(&tvis); - } - - tvis.item.lParam = (LPARAM)PD; - tvis.item.pszText = PD->name; - tvis.item.iImage = tvis.item.iSelectedImage = PD->bShow; - tvis.item.cChildren = PD->pimi->submenu.first != NULL; - - HTREEITEM hti = m_menuItems.InsertItem(&tvis); - if (bIsFirst) { - if (hRoot == NULL) - m_menuItems.SelectItem(hti); - bIsFirst = false; - } - - if (PD->pimi->submenu.first != NULL) { - BuildTreeInternal(pszModule, bReread, PD->pimi->submenu.first, hti); - m_menuItems.Expand(hti, TVE_EXPAND); - } - - lastpos = PD->pos; - } - } - - bool BuildTree(int MenuObjectId, bool bReread) - { - FreeTreeData(); - - TIntMenuObject *pmo = GetMenuObjbyId(MenuObjectId); - if (pmo == NULL || pmo->m_items.first == NULL) - return false; - - char MenuNameItems[256]; - mir_snprintf(MenuNameItems, _countof(MenuNameItems), "%s_Items", pmo->pszName); - - bRebuild = true; - m_menuItems.SendMsg(WM_SETREDRAW, FALSE, 0); - m_menuItems.DeleteAllItems(); - - BuildTreeInternal(MenuNameItems, bReread, pmo->m_items.first, NULL); - - m_menuItems.SendMsg(WM_SETREDRAW, TRUE, 0); - bRebuild = false; - - ShowWindow(m_warning.GetHwnd(), (pmo->m_bUseUserDefinedItems) ? SW_HIDE : SW_SHOW); - m_menuItems.Enable(pmo->m_bUseUserDefinedItems); - m_btnInsert.Enable(pmo->m_bUseUserDefinedItems); - return 1; - } - - bool GetCurrentMenuObjectID(int &result) - { - int iItem = m_menuObjects.GetCurSel(); - if (iItem == -1) - return false; - - result = (int)m_menuObjects.GetItemData(iItem); - return true; - } - - CCtrlListBox m_menuObjects; - CCtrlTreeView m_menuItems; - CCtrlCheck m_radio1, m_radio2, m_enableIcons; - CCtrlEdit m_customName, m_service; - CCtrlButton m_btnInsert, m_btnReset, m_btnSet, m_btnDefault; - CCtrlBase m_warning; - -public: - CGenMenuOptionsPage() : - CDlgBase(g_hInst, IDD_OPT_GENMENU), - m_menuItems(this, IDC_MENUITEMS), - m_menuObjects(this, IDC_MENUOBJECTS), - m_radio1(this, IDC_RADIO1), - m_radio2(this, IDC_RADIO2), - m_enableIcons(this, IDC_DISABLEMENUICONS), - m_btnInsert(this, IDC_INSERTSEPARATOR), - m_btnReset(this, IDC_RESETMENU), - m_btnSet(this, IDC_GENMENU_SET), - m_btnDefault(this, IDC_GENMENU_DEFAULT), - m_customName(this, IDC_GENMENU_CUSTOMNAME), - m_service(this, IDC_GENMENU_SERVICE), - m_warning(this, IDC_NOTSUPPORTWARNING), - bRebuild(false) - { - m_btnSet.OnClick = Callback(this, &CGenMenuOptionsPage::btnSet_Clicked); - m_btnReset.OnClick = Callback(this, &CGenMenuOptionsPage::btnReset_Clicked); - m_btnInsert.OnClick = Callback(this, &CGenMenuOptionsPage::btnInsert_Clicked); - m_btnDefault.OnClick = Callback(this, &CGenMenuOptionsPage::btnDefault_Clicked); - - m_menuObjects.OnSelChange = Callback(this, &CGenMenuOptionsPage::onMenuObjectChanged); - - m_menuItems.SetFlags(MTREE_CHECKBOX | MTREE_DND | MTREE_MULTISELECT); - m_menuItems.OnSelChanged = Callback(this, &CGenMenuOptionsPage::onMenuItemChanged); - m_menuItems.OnBeginDrag = Callback(this, &CGenMenuOptionsPage::onMenuItemDrag); - - m_customName.SetSilent(); - m_service.SetSilent(); - } - - //---- init dialog ------------------------------------------- - virtual void OnInitDialog() - { - iInitMenuValue = db_get_b(NULL, "CList", "MoveProtoMenus", TRUE); - - HIMAGELIST himlCheckBoxes = ImageList_Create(g_iIconSX, g_iIconSY, ILC_COLOR32 | ILC_MASK, 2, 2); - ImageList_AddIcon_IconLibLoaded(himlCheckBoxes, SKINICON_OTHER_NOTICK); - ImageList_AddIcon_IconLibLoaded(himlCheckBoxes, SKINICON_OTHER_TICK); - m_menuItems.SetImageList(himlCheckBoxes, TVSIL_NORMAL); - - if (iInitMenuValue) - m_radio2.SetState(true); - else - m_radio1.SetState(true); - - m_enableIcons.SetState(!bIconsDisabled); - - //---- init menu object list -------------------------------------- - for (int i = 0; i < g_menus.getCount(); i++) { - TIntMenuObject *p = g_menus[i]; - if (p->id != (int)hStatusMenuObject && p->m_bUseUserDefinedItems) - m_menuObjects.AddString(TranslateTS(p->ptszDisplayName), p->id); - } - - m_menuObjects.SetCurSel(0); - RebuildCurrent(); - } - - virtual void OnApply() - { - bIconsDisabled = m_enableIcons.GetState() == 0; - db_set_b(NULL, "CList", "DisableMenuIcons", bIconsDisabled); - SaveTree(); - - int iNewMenuValue = !m_radio1.GetState(); - if (iNewMenuValue != iInitMenuValue) { - db_set_b(NULL, "CList", "MoveProtoMenus", iNewMenuValue); - - RebuildProtoMenus(); - iInitMenuValue = iNewMenuValue; - } - RebuildCurrent(); - } - - virtual void OnDestroy() - { - ImageList_Destroy(m_menuItems.GetImageList(TVSIL_NORMAL)); - FreeTreeData(); - } - - void btnInsert_Clicked(CCtrlButton*) - { - HTREEITEM hti = m_menuItems.GetSelection(); - if (hti == NULL) - return; - - TVITEMEX tvi = { 0 }; - tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM | TVIF_TEXT; - tvi.hItem = hti; - if (!m_menuItems.GetItem(&tvi)) - return; - - MenuItemOptData *PD = new MenuItemOptData(); - PD->id = -1; - PD->name = mir_tstrdup(STR_SEPARATOR); - PD->pos = ((MenuItemOptData *)tvi.lParam)->pos - 1; - - TVINSERTSTRUCT tvis = { 0 }; - tvis.item.lParam = (LPARAM)PD; - tvis.item.pszText = PD->name; - tvis.item.iImage = tvis.item.iSelectedImage = 1; - tvis.hInsertAfter = hti; - tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE; - m_menuItems.InsertItem(&tvis); - - NotifyChange(); - } - - void btnReset_Clicked(CCtrlButton*) - { - int MenuObjectID; - if (GetCurrentMenuObjectID(MenuObjectID)) { - BuildTree(MenuObjectID, false); - NotifyChange(); - } - } - - void btnDefault_Clicked(CCtrlButton*) - { - HTREEITEM hti = m_menuItems.GetSelection(); - if (hti == NULL) - return; - - TVITEMEX tvi; - tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM; - tvi.hItem = hti; - m_menuItems.GetItem(&tvi); - - MenuItemOptData *iod = (MenuItemOptData *)tvi.lParam; - if (iod->name && _tcsstr(iod->name, STR_SEPARATOR)) - return; - - iod->name = mir_tstrdup(iod->defname); - - SaveTree(); - RebuildCurrent(); - NotifyChange(); - } - - void btnSet_Clicked(CCtrlButton*) - { - HTREEITEM hti = m_menuItems.GetSelection(); - if (hti == NULL) - return; - - TVITEMEX tvi; - tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM; - tvi.hItem = hti; - m_menuItems.GetItem(&tvi); - - MenuItemOptData *iod = (MenuItemOptData *)tvi.lParam; - if (iod->name && _tcsstr(iod->name, STR_SEPARATOR)) - return; - - iod->name = m_customName.GetText(); - - SaveTree(); - RebuildCurrent(); - NotifyChange(); - } - - void onMenuObjectChanged(void*) - { - m_initialized = false; - RebuildCurrent(); - m_initialized = true; - } - - void onMenuItemChanged(void*) - { - if (bRebuild) - return; - - m_customName.SetTextA(""); - m_service.SetTextA(""); - - m_btnDefault.Enable(false); - m_btnSet.Enable(false); - m_customName.Enable(false); - - HTREEITEM hti = m_menuItems.GetSelection(); - if (hti == NULL) - return; - - TVITEMEX tvi; - tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM; - tvi.hItem = hti; - m_menuItems.GetItem(&tvi); - if (tvi.lParam == 0) - return; - - MenuItemOptData *iod = (MenuItemOptData *)tvi.lParam; - if (iod->name && _tcsstr(iod->name, STR_SEPARATOR)) - return; - - m_customName.SetText(iod->name); - - if (iod->pimi->submenu.first == NULL && iod->uniqname) - m_service.SetTextA(iod->uniqname); - - m_btnDefault.Enable(mir_tstrcmp(iod->name, iod->defname) != 0); - m_btnSet.Enable(true); - m_customName.Enable(true); - } - - void onMenuItemDrag(CCtrlTreeView::TEventInfo *evt) - { - MenuItemOptData *p = (MenuItemOptData*)evt->nmtv->itemNew.lParam; - if (p->pimi == NULL) - evt->nmhdr->code = 0; // reject an attempt to move a separator - else if (p->pimi->mi.flags & CMIF_UNMOVABLE) - evt->nmhdr->code = 0; // reject an attempt to change item's position - } -}; - -int GenMenuOptInit(WPARAM wParam, LPARAM) -{ - OPTIONSDIALOGPAGE odp = { 0 }; - odp.position = -1000000000; - odp.pszTitle = LPGEN("Menus"); - odp.pszGroup = LPGEN("Customize"); - odp.flags = ODPF_BOLDGROUPS; - odp.pDialog = new CGenMenuOptionsPage(); - Options_AddPage(wParam, &odp); - - return ProtocolOrderOptInit(wParam, 0); -} diff --git a/src/mir_app/src/groupmenu.cpp b/src/mir_app/src/groupmenu.cpp deleted file mode 100644 index ea7c929ee5..0000000000 --- a/src/mir_app/src/groupmenu.cpp +++ /dev/null @@ -1,250 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (ñ) 2012-15 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-08 Miranda ICQ/IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "stdafx.h" - -///////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////// Group MENU ////////////////////////////// - -int hGroupMenuObject, hSubGroupMenuObject; -static HANDLE hEventPreBuildGroupMenu, hEventPreBuildSubGroupMenu; - -// Groupmenu exec param(ownerdata) - -struct GroupMenuExecParam -{ - char *szServiceName; - int Param1, Param2; -}; - -MIR_APP_DLL(HMENU) Menu_BuildGroupMenu() -{ - NotifyEventHooks(hEventPreBuildGroupMenu, 0, 0); - - HMENU hMenu = CreatePopupMenu(); - Menu_Build(hMenu, hGroupMenuObject); - return hMenu; -} - -MIR_APP_DLL(HGENMENU) Menu_AddGroupMenuItem(TMO_MenuItem *pmi, GroupMenuParam *gmp) -{ - GroupMenuExecParam *mmep = (GroupMenuExecParam*)mir_calloc(sizeof(GroupMenuExecParam)); - if (mmep == NULL) - return 0; - - // we need just one parametr. - mmep->szServiceName = mir_strdup(pmi->pszService); - if (gmp != NULL) { - mmep->Param1 = gmp->wParam; - mmep->Param2 = gmp->lParam; - } - - HGENMENU hNewItem = Menu_AddItem(hGroupMenuObject, pmi, mmep); - - char buf[1024]; - mir_snprintf(buf, "%s/%s", pmi->pszService, pmi->name.a); - Menu_ConfigureItem(hNewItem, MCI_OPT_UNIQUENAME, buf); - return hNewItem; -} - -// called with: -// wparam - ownerdata -// lparam - lparam from winproc -INT_PTR GroupMenuExecService(WPARAM wParam, LPARAM lParam) -{ - if (wParam != 0) { - GroupMenuExecParam * mmep = (GroupMenuExecParam *)wParam; - if (!mir_strcmp(mmep->szServiceName, "Help/AboutCommand")) { - //bug in help.c,it used wparam as parent window handle without reason. - mmep->Param1 = 0; - CallService(mmep->szServiceName, mmep->Param1, lParam); - } - else CallService(mmep->szServiceName, mmep->Param1, mmep->Param2); - } - return 1; -} - -INT_PTR FreeOwnerDataGroupMenu(WPARAM, LPARAM lParam) -{ - GroupMenuExecParam * mmep = (GroupMenuExecParam *)lParam; - if (mmep != NULL) { - mir_free(mmep->szServiceName); - mir_free(mmep); - } - - return 0; -} - -INT_PTR HideGroupsHelper(WPARAM, LPARAM) -{ - int newVal = !(GetWindowLongPtr(cli.hwndContactTree, GWL_STYLE) & CLS_HIDEEMPTYGROUPS); - db_set_b(NULL, "CList", "HideEmptyGroups", (BYTE)newVal); - SendMessage(cli.hwndContactTree, CLM_SETHIDEEMPTYGROUPS, newVal, 0); - return 0; -} - -INT_PTR UseGroupsHelper(WPARAM, LPARAM) -{ - int newVal = !(GetWindowLongPtr(cli.hwndContactTree, GWL_STYLE) & CLS_USEGROUPS); - db_set_b(NULL, "CList", "UseGroups", (BYTE)newVal); - SendMessage(cli.hwndContactTree, CLM_SETUSEGROUPS, newVal,0); - return 0; -} - -INT_PTR HideOfflineRootHelper(WPARAM, LPARAM) -{ - SendMessage(cli.hwndContactTree, CLM_SETHIDEOFFLINEROOT, - !SendMessage(cli.hwndContactTree, CLM_GETHIDEOFFLINEROOT, 0, 0), - 0); - return 0; -} - -INT_PTR CreateGroupHelper(WPARAM, LPARAM) -{ - SendMessage(cli.hwndContactTree, CLM_SETHIDEEMPTYGROUPS, 0, 0); - SendMessage(cli.hwndContactTree, CLM_SETUSEGROUPS, 1, 0); - Clist_CreateGroup(0, 0); - return 0; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////// SubGroup MENU ////////////////////////////// - -struct SubGroupMenuExecParam -{ - char *szServiceName; - int Param1, Param2; -}; - -MIR_APP_DLL(HMENU) Menu_BuildSubGroupMenu(ClcGroup *group) -{ - NotifyEventHooks(hEventPreBuildSubGroupMenu, (WPARAM)group, 0); - - HMENU hMenu = CreatePopupMenu(); - Menu_Build(hMenu, hSubGroupMenuObject, (WPARAM)group, 0); - return hMenu; -} - -HMENU cliBuildGroupPopupMenu(ClcGroup *group) -{ - return Menu_BuildSubGroupMenu(group); -} - -MIR_APP_DLL(HGENMENU) Menu_AddSubGroupMenuItem(TMO_MenuItem *pmi, GroupMenuParam *gmp) -{ - SubGroupMenuExecParam *mmep = (SubGroupMenuExecParam*)mir_calloc(sizeof(SubGroupMenuExecParam)); - if (mmep == NULL) - return 0; - - // we need just one parametr. - mmep->szServiceName = mir_strdup(pmi->pszService); - if (gmp != NULL) { - mmep->Param1 = gmp->wParam; - mmep->Param2 = gmp->lParam; - } - - HGENMENU hNewItem = Menu_AddItem(hSubGroupMenuObject, pmi, mmep); - - char buf[1024]; - mir_snprintf(buf, "%s/%s", pmi->pszService, pmi->name.a); - Menu_ConfigureItem(hNewItem, MCI_OPT_UNIQUENAME, buf); - return hNewItem; -} - -static INT_PTR SubGroupMenuCheckService(WPARAM wParam, LPARAM) -{ - TCheckProcParam * CParam = (TCheckProcParam*)wParam; - if (CParam) { - SubGroupMenuExecParam * mmep = (SubGroupMenuExecParam *)(CParam->MenuItemOwnerData); - if (mmep) - mmep->Param2 = CParam->lParam; - } - return 1; -} - -// called with: -// wparam - ownerdata -// lparam - lparam from winproc -static INT_PTR SubGroupMenuExecService(WPARAM wParam, LPARAM lParam) -{ - if (wParam != 0) { - SubGroupMenuExecParam * mmep = (SubGroupMenuExecParam *)wParam; - if (!mir_strcmp(mmep->szServiceName, "Help/AboutCommand")) { - //bug in help.c,it used wparam as parent window handle without reason. - mmep->Param1 = 0; - CallService(mmep->szServiceName, mmep->Param1, lParam); - } - else CallService(mmep->szServiceName, mmep->Param1, lParam); - } - return 1; -} - -static INT_PTR FreeOwnerDataSubGroupMenu(WPARAM, LPARAM lParam) -{ - SubGroupMenuExecParam * mmep = (SubGroupMenuExecParam *)lParam; - if (mmep != NULL) { - mir_free(mmep->szServiceName); - mir_free(mmep); - } - return 0; -} - -// wparam menu handle to pass to clc.c -// lparam WM_COMMAND HWND -static INT_PTR GroupMenuExecProxy(WPARAM wParam, LPARAM lParam) -{ - SendMessage(lParam ? (HWND)lParam : (HWND)cli.hwndContactTree, WM_COMMAND, wParam, 0); - return 0; -} - -void InitGroupMenus(void) -{ - // Group menu - CreateServiceFunction("CLISTMENUSGroup/ExecService", GroupMenuExecService); - CreateServiceFunction("CLISTMENUSGroup/FreeOwnerDataGroupMenu", FreeOwnerDataGroupMenu); - CreateServiceFunction("CLISTMENUSGroup/HideGroupsHelper", HideGroupsHelper); - CreateServiceFunction("CLISTMENUSGroup/UseGroupsHelper", UseGroupsHelper); - CreateServiceFunction("CLISTMENUSGroup/HideOfflineRootHelper", HideOfflineRootHelper); - CreateServiceFunction("CLISTMENUSGroup/CreateGroupHelper", CreateGroupHelper); - - hEventPreBuildGroupMenu = CreateHookableEvent(ME_CLIST_PREBUILDGROUPMENU); - - hGroupMenuObject = Menu_AddObject("GroupMenu", LPGEN("Group menu"), 0, "CLISTMENUSGroup/ExecService"); - Menu_ConfigureObject(hGroupMenuObject, MCO_OPT_USERDEFINEDITEMS, TRUE); - Menu_ConfigureObject(hGroupMenuObject, MCO_OPT_FREE_SERVICE, "CLISTMENUSGroup/FreeOwnerDataGroupMenu"); - Menu_ConfigureObject(hGroupMenuObject, MCO_OPT_ONADD_SERVICE, "CLISTMENUSGroup/GroupMenuOnAddService"); - - // SubGroup menu - CreateServiceFunction("CLISTMENUSSubGroup/ExecService", SubGroupMenuExecService); - CreateServiceFunction("CLISTMENUSSubGroup/FreeOwnerDataSubGroupMenu", FreeOwnerDataSubGroupMenu); - CreateServiceFunction("CLISTMENUSSubGroup/SubGroupMenuCheckService", SubGroupMenuCheckService); - CreateServiceFunction("CLISTMENUSSubGroup/GroupMenuExecProxy", GroupMenuExecProxy); - - hEventPreBuildSubGroupMenu = CreateHookableEvent(ME_CLIST_PREBUILDSUBGROUPMENU); - - hSubGroupMenuObject = Menu_AddObject("SubGroupMenu", LPGEN("Subgroup menu"), 0, "CLISTMENUSSubGroup/ExecService"); - Menu_ConfigureObject(hSubGroupMenuObject, MCO_OPT_USERDEFINEDITEMS, TRUE); - Menu_ConfigureObject(hSubGroupMenuObject, MCO_OPT_FREE_SERVICE, "CLISTMENUSSubGroup/FreeOwnerDataSubGroupMenu"); - Menu_ConfigureObject(hSubGroupMenuObject, MCO_OPT_CHECK_SERVICE, "CLISTMENUSSubGroup/SubGroupMenuCheckService"); -} diff --git a/src/mir_app/src/menu_clist.cpp b/src/mir_app/src/menu_clist.cpp new file mode 100644 index 0000000000..03f5830db9 --- /dev/null +++ b/src/mir_app/src/menu_clist.cpp @@ -0,0 +1,1206 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (ñ) 2012-15 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "stdafx.h" +#pragma hdrstop + +#include "m_hotkeys.h" + +#include "clc.h" +#include "genmenu.h" + +void InitGroupMenus(void); +void InitFramesMenus(void); +void InitTrayMenus(void); + +#define MS_CLIST_HKSTATUS "Clist/HK/SetStatus" + +#define FIRSTCUSTOMMENUITEMID 30000 +#define MENU_CUSTOMITEMMAIN 0x80000000 +//#define MENU_CUSTOMITEMCONTEXT 0x40000000 +//#define MENU_CUSTOMITEMFRAME 0x20000000 + +typedef struct { + WORD id; + int iconId; + TMO_MenuItem mi; +} + CListIntMenuItem, *lpCListIntMenuItem; + +// new menu sys +int hMainMenuObject = 0, hContactMenuObject = 0, hStatusMenuObject = 0; +int UnloadMoveToGroup(void); + +int statustopos(int status); +void Proto_SetStatus(const char *szProto, unsigned status); + +bool prochotkey; + +HANDLE hPreBuildMainMenuEvent, hStatusModeChangeEvent, hPreBuildContactMenuEvent; + +static HMENU hMainMenu, hStatusMenu = 0; +const int statusModeList[MAX_STATUS_COUNT] = +{ + ID_STATUS_OFFLINE, ID_STATUS_ONLINE, ID_STATUS_AWAY, ID_STATUS_NA, ID_STATUS_OCCUPIED, + ID_STATUS_DND, ID_STATUS_FREECHAT, ID_STATUS_INVISIBLE, ID_STATUS_ONTHEPHONE, ID_STATUS_OUTTOLUNCH +}; + +const int skinIconStatusList[MAX_STATUS_COUNT] = +{ + SKINICON_STATUS_OFFLINE, SKINICON_STATUS_ONLINE, SKINICON_STATUS_AWAY, SKINICON_STATUS_NA, SKINICON_STATUS_OCCUPIED, + SKINICON_STATUS_DND, SKINICON_STATUS_FREE4CHAT, SKINICON_STATUS_INVISIBLE, SKINICON_STATUS_ONTHEPHONE, SKINICON_STATUS_OUTTOLUNCH +}; + +static const int statusModePf2List[MAX_STATUS_COUNT] = +{ + 0xFFFFFFFF, PF2_ONLINE, PF2_SHORTAWAY, PF2_LONGAWAY, PF2_LIGHTDND, + PF2_HEAVYDND, PF2_FREECHAT, PF2_INVISIBLE, PF2_ONTHEPHONE, PF2_OUTTOLUNCH +}; + +static INT_PTR statusHotkeys[MAX_STATUS_COUNT]; + +TMO_IntMenuItem **hStatusMainMenuHandles; +int hStatusMainMenuHandlesCnt; + +struct tStatusMenuHandles +{ + int protoindex; + int protostatus[MAX_STATUS_COUNT]; + TMO_IntMenuItem *menuhandle[MAX_STATUS_COUNT]; +}; + +tStatusMenuHandles *hStatusMenuHandles; +int hStatusMenuHandlesCnt; + +struct BuildContactParam +{ + char *szProto; + int isOnList; + int isOnline; +}; + +struct MenuItemData +{ + HMENU OwnerMenu; + int position; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// service functions + +void FreeMenuProtos(void) +{ + if (cli.menuProtos) { + for (int i = 0; i < cli.menuProtoCount; i++) + mir_free(cli.menuProtos[i].szProto); + mir_free(cli.menuProtos); + cli.menuProtos = NULL; + } + cli.menuProtoCount = 0; +} + +////////////////////////////////////////////////////////////////////////// + +int fnGetAverageMode(int *pNetProtoCount) +{ + int netProtoCount = 0, averageMode = 0; + + for (int i = 0; i < accounts.getCount(); i++) { + PROTOACCOUNT *pa = accounts[i]; + if (cli.pfnGetProtocolVisibility(pa->szModuleName) == 0 || Proto_IsAccountLocked(pa)) + continue; + + netProtoCount++; + + if (averageMode == 0) + averageMode = CallProtoServiceInt(NULL, pa->szModuleName, PS_GETSTATUS, 0, 0); + else if (averageMode > 0 && averageMode != CallProtoServiceInt(NULL, pa->szModuleName, PS_GETSTATUS, 0, 0)) { + averageMode = -1; + if (pNetProtoCount == NULL) + break; + } + } + + if (pNetProtoCount) *pNetProtoCount = netProtoCount; + return averageMode; +} + +static int RecursiveDeleteMenu(HMENU hMenu) +{ + int cnt = GetMenuItemCount(hMenu); + for (int i = 0; i < cnt; i++) { + HMENU submenu = GetSubMenu(hMenu, 0); + if (submenu) DestroyMenu(submenu); + DeleteMenu(hMenu, 0, MF_BYPOSITION); + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// MAIN MENU + +struct MainMenuExecParam +{ + char *szServiceName; + TCHAR *szMenuName; + TMO_IntMenuItem *pimi; +}; + +MIR_APP_DLL(HMENU) Menu_BuildMainMenu(void) +{ + NotifyEventHooks(hPreBuildMainMenuEvent, 0, 0); + + Menu_Build(hMainMenu, hMainMenuObject); + DrawMenuBar(cli.hwndContactList); + return hMainMenu; +} + +MIR_APP_DLL(HMENU) Menu_GetMainMenu(void) +{ + RecursiveDeleteMenu(hMainMenu); + return Menu_BuildMainMenu(); +} + +MIR_APP_DLL(HGENMENU) Menu_AddMainMenuItem(TMO_MenuItem *pmi) +{ + MainMenuExecParam *mmep = (MainMenuExecParam*)mir_alloc(sizeof(MainMenuExecParam)); + if (mmep == NULL) + return 0; + + //we need just one parametr. + mmep->szServiceName = mir_strdup(pmi->pszService); + mmep->szMenuName = pmi->name.t; + + TMO_IntMenuItem *pimi = Menu_AddItem(hMainMenuObject, pmi, mmep); + if (pimi == NULL) + return NULL; + + mmep->pimi = pimi; + + const char* name; + bool needFree = false; + + if (pmi->pszService) + name = pmi->pszService; + else if (pmi->flags & CMIF_UNICODE) { + name = mir_t2a(pmi->name.t); + needFree = true; + } + else name = pmi->name.a; + + Menu_ConfigureItem(pimi, MCI_OPT_UNIQUENAME, name); + if (needFree) + mir_free((void*)name); + + return pimi; +} + +// called with: +// wparam - ownerdata +// lparam - lparam from winproc +INT_PTR MainMenuExecService(WPARAM wParam, LPARAM lParam) +{ + MainMenuExecParam *mmep = (MainMenuExecParam*)wParam; + if (mmep != NULL) { + CallService(mmep->szServiceName, mmep->pimi->execParam, lParam); + } + return 1; +} + +INT_PTR FreeOwnerDataMainMenu(WPARAM, LPARAM lParam) +{ + MainMenuExecParam *mmep = (MainMenuExecParam*)lParam; + if (mmep != NULL) { + FreeAndNil((void**)&mmep->szServiceName); + FreeAndNil((void**)&mmep); + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CONTACT MENU + +struct ContactMenuExecParam +{ + char *szServiceName; + char *pszContactOwner; + TMO_IntMenuItem *pimi; +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(HGENMENU) Menu_AddContactMenuItem(TMO_MenuItem *pmi, const char *pszProto) +{ + // owner data + ContactMenuExecParam *cmep = (ContactMenuExecParam*)mir_calloc(sizeof(ContactMenuExecParam)); + cmep->szServiceName = mir_strdup(pmi->pszService); + if (pszProto != NULL) + cmep->pszContactOwner = mir_strdup(pszProto); + + // may be need to change how UniqueName is formed? + TMO_IntMenuItem *pimi = Menu_AddItem(hContactMenuObject, pmi, cmep); + if (pimi == NULL) + return NULL; + + cmep->pimi = pimi; + + if (pszProto == NULL) + pszProto = ""; + + char buf[256]; + if (pmi->pszService) { + mir_snprintf(buf, "%s/%s", pszProto, (pmi->pszService) ? pmi->pszService : ""); + Menu_ConfigureItem(pimi, MCI_OPT_UNIQUENAME, buf); + } + else if (pmi->name.t) { + if (pmi->flags & CMIF_UNICODE) + mir_snprintf(buf, "%s/NoService/%S", pszProto, pmi->name.t); + else + mir_snprintf(buf, "%s/NoService/%s", pszProto, pmi->name.a); + Menu_ConfigureItem(pimi, MCI_OPT_UNIQUENAME, buf); + } + return pimi; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +EXTERN_C MIR_APP_DLL(HMENU) Menu_BuildContactMenu(MCONTACT hContact) +{ + NotifyEventHooks(hPreBuildContactMenuEvent, hContact, 0); + + char *szProto = GetContactProto(hContact); + + BuildContactParam bcp; + bcp.szProto = szProto; + bcp.isOnList = (db_get_b(hContact, "CList", "NotOnList", 0) == 0); + bcp.isOnline = (szProto != NULL && ID_STATUS_OFFLINE != db_get_w(hContact, szProto, "Status", ID_STATUS_OFFLINE)); + + HMENU hMenu = CreatePopupMenu(); + Menu_Build(hMenu, hContactMenuObject, (WPARAM)&bcp); + return hMenu; +} + +// true - ok, false ignore +static INT_PTR ContactMenuCheckService(WPARAM wParam, LPARAM) +{ + TCheckProcParam *pcpp = (TCheckProcParam*)wParam; + if (pcpp == NULL) + return FALSE; + + BuildContactParam *bcp = (BuildContactParam*)pcpp->wParam; + if (bcp == NULL) + return FALSE; + + ContactMenuExecParam *cmep = (ContactMenuExecParam*)pcpp->MenuItemOwnerData; + if (cmep == NULL) //this is root...build it + return TRUE; + + if (cmep->pszContactOwner != NULL) { + if (bcp->szProto == NULL) return FALSE; + if (mir_strcmp(cmep->pszContactOwner, bcp->szProto)) return FALSE; + } + + TMO_MenuItem &mi = pcpp->MenuItemHandle->mi; + if (mi.flags & CMIF_HIDDEN) return FALSE; + if (mi.flags & CMIF_NOTONLIST && bcp->isOnList) return FALSE; + if (mi.flags & CMIF_NOTOFFLIST && !bcp->isOnList) return FALSE; + if (mi.flags & CMIF_NOTONLINE && bcp->isOnline) return FALSE; + if (mi.flags & CMIF_NOTOFFLINE && !bcp->isOnline) return FALSE; + return TRUE; +} + +// called with: +// wparam - ContactMenuExecParam* +// lparam - lparam from winproc +static INT_PTR ContactMenuExecService(WPARAM wParam, LPARAM lParam) +{ + if (wParam != 0) { + ContactMenuExecParam *cmep = (ContactMenuExecParam*)wParam; + if (cmep->pszContactOwner && cmep->szServiceName && cmep->szServiceName[0] == '/') + ProtoCallService(cmep->pszContactOwner, cmep->szServiceName, lParam, cmep->pimi->execParam); + else + CallService(cmep->szServiceName, lParam, cmep->pimi->execParam); + } + return 0; +} + +// called with: +// lparam - ContactMenuExecParam* +static INT_PTR FreeOwnerDataContactMenu(WPARAM, LPARAM lParam) +{ + ContactMenuExecParam *cmep = (ContactMenuExecParam*)lParam; + if (cmep != NULL) { + FreeAndNil((void**)&cmep->szServiceName); + FreeAndNil((void**)&cmep->pszContactOwner); + FreeAndNil((void**)&cmep); + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// STATUS MENU + +struct StatusMenuExecParam +{ + char *szProto; // This is unique protoname + int protoindex; + int status; + + BOOL custom; + char *svc; + HANDLE hMenuItem; +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(HGENMENU) Menu_AddStatusMenuItem(TMO_MenuItem *pmi, const char *pszProto) +{ + TMO_IntMenuItem *pRoot = MO_GetIntMenuItem(pmi->root); + + // owner data + StatusMenuExecParam *smep = NULL; + if (pmi->pszService) { + smep = (StatusMenuExecParam*)mir_calloc(sizeof(StatusMenuExecParam)); + smep->custom = TRUE; + smep->svc = mir_strdup(pmi->pszService); + smep->szProto = mir_strdup(pszProto); + } + + TMO_IntMenuItem *pimi = Menu_AddItem(hStatusMenuObject, pmi, smep); + if (pimi == NULL) + return NULL; + + if (smep) + smep->hMenuItem = pimi; + + char buf[MAX_PATH + 64]; + char *p = (pRoot) ? mir_t2a(pRoot->mi.name.t) : NULL; + mir_snprintf(buf, "%s/%s", (p) ? p : "", pmi->pszService ? pmi->pszService : ""); + mir_free(p); + + Menu_ConfigureItem(pimi, MCI_OPT_UNIQUENAME, buf); + return pimi; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(HMENU) Menu_GetStatusMenu() +{ + RecursiveDeleteMenu(hStatusMenu); + + Menu_Build(hStatusMenu, hStatusMenuObject); + return hStatusMenu; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +BOOL FindMenuHandleByGlobalID(HMENU hMenu, TMO_IntMenuItem *id, MenuItemData* itdat) +{ + if (!itdat) + return FALSE; + + MENUITEMINFO mii = { 0 }; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_SUBMENU | MIIM_DATA; + for (int i = GetMenuItemCount(hMenu) - 1; i >= 0; i--) { + GetMenuItemInfo(hMenu, i, TRUE, &mii); + if (mii.fType == MFT_SEPARATOR) + continue; + + BOOL inSub = FALSE; + if (mii.hSubMenu) + inSub = FindMenuHandleByGlobalID(mii.hSubMenu, id, itdat); + if (inSub) + return inSub; + + TMO_IntMenuItem *pimi = MO_GetIntMenuItem((HGENMENU)mii.dwItemData); + if (pimi != NULL) { + if (pimi == id) { + itdat->OwnerMenu = hMenu; + itdat->position = i; + return TRUE; + } + } + } + + return FALSE; +} + +INT_PTR StatusMenuCheckService(WPARAM wParam, LPARAM) +{ + TCheckProcParam *pcpp = (TCheckProcParam*)wParam; + if (!pcpp) + return TRUE; + + TMO_IntMenuItem *pimi = MO_GetIntMenuItem(pcpp->MenuItemHandle); + if (!pimi) + return TRUE; + + StatusMenuExecParam *smep = (StatusMenuExecParam*)pcpp->MenuItemOwnerData; + if (smep && !smep->status && smep->custom) { + if (wildcmp(smep->svc, "*XStatus*")) { + int XStatus; + CUSTOM_STATUS cs = { sizeof(cs) }; + cs.flags = CSSF_MASK_STATUS; + cs.status = &XStatus; + if (CallProtoServiceInt(NULL, smep->szProto, PS_GETCUSTOMSTATUSEX, 0, (LPARAM)&cs) != 0) + XStatus = 0; + + char buf[255]; + mir_snprintf(buf, "*XStatus%d", XStatus); + + bool check = wildcmp(smep->svc, buf) != 0; + bool reset = wildcmp(smep->svc, "*XStatus0") != 0; + + if (check) + pimi->mi.flags |= CMIF_CHECKED; + else + pimi->mi.flags &= ~CMIF_CHECKED; + + if (reset || check) { + TMO_IntMenuItem *timiParent = MO_GetIntMenuItem(pimi->mi.root); + if (timiParent) { + LPTSTR ptszName = TranslateTH(pimi->mi.hLangpack, pimi->mi.hIcolibItem ? pimi->mi.name.t : LPGENT("Custom status")); + + timiParent = MO_GetIntMenuItem(pimi->mi.root); + + MenuItemData it = { 0 }; + if (FindMenuHandleByGlobalID(hStatusMenu, timiParent, &it)) { + TCHAR d[100]; + GetMenuString(it.OwnerMenu, it.position, d, _countof(d), MF_BYPOSITION); + + MENUITEMINFO mii = { 0 }; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_STRING | MIIM_STATE; + if (pimi->iconId != -1) { + mii.fMask |= MIIM_BITMAP; + if (IsWinVerVistaPlus() && IsThemeActive()) { + if (pimi->hBmp == NULL) + pimi->hBmp = ConvertIconToBitmap(NULL, pimi->parent->m_hMenuIcons, pimi->iconId); + mii.hbmpItem = pimi->hBmp; + } + else mii.hbmpItem = HBMMENU_CALLBACK; + } + + mii.fState |= (check && !reset ? MFS_CHECKED : MFS_UNCHECKED); + mii.dwTypeData = ptszName; + SetMenuItemInfo(it.OwnerMenu, it.position, TRUE, &mii); + } + + Menu_ModifyItem(pimi->mi.root, ptszName); + + timiParent->iconId = pimi->iconId; + if (timiParent->hBmp) DeleteObject(timiParent->hBmp); + timiParent->hBmp = NULL; + } + } + } + } + else if (smep && smep->status && !smep->custom) { + int curProtoStatus = (smep->szProto) ? CallProtoServiceInt(NULL, smep->szProto, PS_GETSTATUS, 0, 0) : cli.pfnGetAverageMode(NULL); + if (smep->status == curProtoStatus) + pimi->mi.flags |= CMIF_CHECKED; + else + pimi->mi.flags &= ~CMIF_CHECKED; + } + else if ((!smep || smep->szProto) && pimi->mi.name.a) { + int curProtoStatus = 0; + BOOL IconNeedDestroy = FALSE; + char* prot; + if (smep) + prot = smep->szProto; + else { + char *prn = mir_u2a(pimi->mi.name.t); + prot = NEWSTR_ALLOCA(prn); + if (prn) mir_free(prn); + } + if (Proto_GetAccount(prot) == NULL) + return TRUE; + + if ((curProtoStatus = CallProtoServiceInt(NULL, prot, PS_GETSTATUS, 0, 0)) == CALLSERVICE_NOTFOUND) + curProtoStatus = 0; + + if (curProtoStatus >= ID_STATUS_OFFLINE && curProtoStatus < ID_STATUS_IDLE) + pimi->mi.hIcolibItem = Skin_LoadProtoIcon(prot, curProtoStatus); + else { + pimi->mi.hIcolibItem = (HICON)CallProtoServiceInt(NULL, prot, PS_LOADICON, PLI_PROTOCOL | PLIF_SMALL, 0); + if (pimi->mi.hIcolibItem == (HICON)CALLSERVICE_NOTFOUND) + pimi->mi.hIcolibItem = NULL; + else + IconNeedDestroy = TRUE; + } + + if (pimi->mi.hIcolibItem) { + Menu_ModifyItem(pimi, NULL, pimi->mi.hIcolibItem); + if (IconNeedDestroy) { + DestroyIcon((HICON)pimi->mi.hIcolibItem); + pimi->mi.hIcolibItem = NULL; + } + else IcoLib_ReleaseIcon((HICON)pimi->mi.hIcolibItem); + } + } + + return TRUE; +} + +INT_PTR StatusMenuExecService(WPARAM wParam, LPARAM) +{ + StatusMenuExecParam *smep = (StatusMenuExecParam*)wParam; + if (smep == NULL) + return 0; + + if (smep->custom) { + if (smep->svc && *smep->svc) { + if (smep->szProto && *smep->svc == '/') + ProtoCallService(smep->szProto, smep->svc, 0, (LPARAM)smep->hMenuItem); + else + CallService(smep->svc, 0, (LPARAM)smep->hMenuItem); + } + return 0; + } + + if (smep->status == 0 && smep->protoindex != 0 && smep->szProto != NULL) { + char *prot = smep->szProto; + char szHumanName[64] = { 0 }; + PROTOACCOUNT *acc = Proto_GetAccount(smep->szProto); + bool bIsLocked = !Proto_IsAccountLocked(acc); + db_set_b(NULL, prot, "LockMainStatus", bIsLocked); + + CallProtoServiceInt(NULL, smep->szProto, PS_GETNAME, _countof(szHumanName), (LPARAM)szHumanName); + + TMO_IntMenuItem *pimi = MO_GetIntMenuItem((HGENMENU)smep->protoindex); + if (pimi == NULL) + return 0; + + TMO_IntMenuItem *root = (TMO_IntMenuItem*)pimi->mi.root; + TCHAR buf[256], *ptszName; + if (bIsLocked) { + pimi->mi.flags |= CMIF_CHECKED; + if (cli.bDisplayLocked) { + mir_sntprintf(buf, TranslateT("%s (locked)"), acc->tszAccountName); + ptszName = buf; + } + else ptszName = acc->tszAccountName; + } + else { + ptszName = acc->tszAccountName; + pimi->mi.flags &= ~CMIF_CHECKED; + } + replaceStrT(pimi->mi.name.t, ptszName); + replaceStrT(root->mi.name.t, ptszName); + + if (cli.hwndStatus) + InvalidateRect(cli.hwndStatus, NULL, TRUE); + return 0; + } + + if (smep->szProto != NULL) { + Proto_SetStatus(smep->szProto, smep->status); + NotifyEventHooks(hStatusModeChangeEvent, smep->status, (LPARAM)smep->szProto); + return 0; + } + + int MenusProtoCount = 0; + + for (int i = 0; i < accounts.getCount(); i++) + if (cli.pfnGetProtocolVisibility(accounts[i]->szModuleName)) + MenusProtoCount++; + + cli.currentDesiredStatusMode = smep->status; + + for (int j = 0; j < accounts.getCount(); j++) { + PROTOACCOUNT *pa = accounts[j]; + if (!Proto_IsAccountEnabled(pa)) + continue; + if (MenusProtoCount > 1 && Proto_IsAccountLocked(pa)) + continue; + + Proto_SetStatus(pa->szModuleName, cli.currentDesiredStatusMode); + } + NotifyEventHooks(hStatusModeChangeEvent, cli.currentDesiredStatusMode, 0); + db_set_w(NULL, "CList", "Status", (WORD)cli.currentDesiredStatusMode); + return 1; +} + +INT_PTR FreeOwnerDataStatusMenu(WPARAM, LPARAM lParam) +{ + StatusMenuExecParam *smep = (StatusMenuExecParam*)lParam; + if (smep != NULL) { + mir_free(smep->szProto); + mir_free(smep->svc); + mir_free(smep); + } + + return (0); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Other menu functions + +INT_PTR MenuProcessCommand(WPARAM wParam, LPARAM lParam) +{ + WORD cmd = LOWORD(wParam); + + if (HIWORD(wParam) & MPCF_MAINMENU) { + int hst = LOWORD(wParam); + if (hst >= ID_STATUS_OFFLINE && hst <= ID_STATUS_OUTTOLUNCH) { + int pos = statustopos(hst); + if (pos != -1 && hStatusMainMenuHandles != NULL) + return Menu_ProcessCommand(hStatusMainMenuHandles[pos], lParam); + } + } + + if (!(cmd >= CLISTMENUIDMIN && cmd <= CLISTMENUIDMAX)) + return 0; // DO NOT process ids outside from clist menu id range v0.7.0.27+ + + //process old menu sys + if (HIWORD(wParam) & MPCF_CONTACTMENU) + return MO_ProcessCommandBySubMenuIdent((int)hContactMenuObject, LOWORD(wParam), lParam); + + //unknown old menu + return Menu_ProcessCommandById(LOWORD(wParam), lParam); +} + +BOOL FindMenuHanleByGlobalID(HMENU hMenu, TMO_IntMenuItem *id, MenuItemData* itdat) +{ + if (!itdat) + return FALSE; + + BOOL inSub = FALSE; + + MENUITEMINFO mii = { 0 }; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_SUBMENU | MIIM_DATA; + for (int i = GetMenuItemCount(hMenu) - 1; i >= 0; i--) { + GetMenuItemInfo(hMenu, i, TRUE, &mii); + if (mii.fType == MFT_SEPARATOR) + continue; + + if (mii.hSubMenu) + inSub = FindMenuHanleByGlobalID(mii.hSubMenu, id, itdat); + if (inSub) + return inSub; + + TMO_IntMenuItem *pimi = MO_GetIntMenuItem((HGENMENU)mii.dwItemData); + if (pimi != NULL) { + if (pimi == id) { + itdat->OwnerMenu = hMenu; + itdat->position = i; + return TRUE; + } + } + } + + return FALSE; +} + +static INT_PTR MenuProcessHotkey(WPARAM vKey, LPARAM) +{ + prochotkey = true; + + bool res = + Menu_ProcessHotKey(hStatusMenuObject, vKey) || + Menu_ProcessHotKey(hMainMenuObject, vKey); + + prochotkey = false; + + return res; +} + +static int MenuIconsChanged(WPARAM, LPARAM) +{ + //just rebuild menu + RebuildMenuOrder(); + cli.pfnCluiProtocolStatusChanged(0, 0); + return 0; +} + +static INT_PTR SetStatusMode(WPARAM wParam, LPARAM) +{ + prochotkey = true; + MenuProcessCommand(MAKEWPARAM(LOWORD(wParam), MPCF_MAINMENU), 0); + prochotkey = false; + return 0; +} + +int fnGetProtocolVisibility(const char *accName) +{ + if (accName) { + PROTOACCOUNT *pa = Proto_GetAccount(accName); + if (pa && pa->bIsVisible && Proto_IsAccountEnabled(pa) && pa->ppro) { + PROTOCOLDESCRIPTOR *pd = Proto_IsProtocolLoaded(pa->szProtoName); + if (pd == NULL || pd->type != PROTOTYPE_PROTOCOL) + return FALSE; + + return (pa->ppro->GetCaps(PFLAGNUM_2, 0) & ~pa->ppro->GetCaps(PFLAGNUM_5, 0)); + } + } + + return FALSE; +} + +int fnGetProtoIndexByPos(PROTOCOLDESCRIPTOR **proto, int protoCnt, int Pos) +{ + char buf[10]; + _itoa(Pos, buf, 10); + + DBVARIANT dbv; + if (!db_get_s(NULL, "Protocols", buf, &dbv)) { + for (int p = 0; p < protoCnt; p++) { + if (mir_strcmp(proto[p]->szName, dbv.pszVal) == 0) { + db_free(&dbv); + return p; + } + } + + db_free(&dbv); + } + + return -1; +} + +int fnGetAccountIndexByPos(int Pos) +{ + for (int i = 0; i < accounts.getCount(); i++) + if (accounts[i]->iOrder == Pos) + return i; + + return -1; +} + +void RebuildMenuOrder(void) +{ + BYTE bHideStatusMenu = db_get_b(NULL, "CLUI", "DontHideStatusMenu", 0); // cool perversion, though + + //clear statusmenu + RecursiveDeleteMenu(hStatusMenu); + + //status menu + if (hStatusMenuObject != 0) { + Menu_RemoveObject(hStatusMenuObject); + mir_free(hStatusMainMenuHandles); + mir_free(hStatusMenuHandles); + } + + hStatusMenuObject = Menu_AddObject("StatusMenu", LPGEN("Status menu"), "StatusMenuCheckService", "StatusMenuExecService"); + Menu_ConfigureObject(hStatusMenuObject, MCO_OPT_FREE_SERVICE, (INT_PTR)"CLISTMENUS/FreeOwnerDataStatusMenu"); + + hStatusMainMenuHandles = (TMO_IntMenuItem**)mir_calloc(_countof(statusModeList) * sizeof(TMO_IntMenuItem*)); + hStatusMainMenuHandlesCnt = _countof(statusModeList); + + hStatusMenuHandles = (tStatusMenuHandles*)mir_calloc(sizeof(tStatusMenuHandles)*accounts.getCount()); + hStatusMenuHandlesCnt = accounts.getCount(); + + FreeMenuProtos(); + + for (int s = 0; s < accounts.getCount(); s++) { + int i = cli.pfnGetAccountIndexByPos(s); + if (i == -1) + continue; + + PROTOACCOUNT *pa = accounts[i]; + int pos = 0; + if (!bHideStatusMenu && !cli.pfnGetProtocolVisibility(pa->szModuleName)) + continue; + + DWORD flags = pa->ppro->GetCaps(PFLAGNUM_2, 0) & ~pa->ppro->GetCaps(PFLAGNUM_5, 0); + HICON ic; + TCHAR tbuf[256]; + + // adding root + CMenuItem mi; + mi.flags = CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; + mi.position = pos++; + mi.hIcon = ic = (HICON)CallProtoServiceInt(NULL, pa->szModuleName, PS_LOADICON, PLI_PROTOCOL | PLIF_SMALL, 0); + + if (Proto_IsAccountLocked(pa) && cli.bDisplayLocked) { + mir_sntprintf(tbuf, _countof(tbuf), TranslateT("%s (locked)"), pa->tszAccountName); + mi.name.t = tbuf; + } + else mi.name.t = pa->tszAccountName; + + // owner data + StatusMenuExecParam *smep = (StatusMenuExecParam*)mir_calloc(sizeof(StatusMenuExecParam)); + smep->szProto = mir_strdup(pa->szModuleName); + TMO_IntMenuItem *rootmenu = Menu_AddItem(hStatusMenuObject, &mi, smep); + + memset(&mi, 0, sizeof(mi)); + mi.flags = CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; + mi.root = rootmenu; + mi.position = pos++; + mi.hIcon = ic; + + // owner data + smep = (StatusMenuExecParam*)mir_calloc(sizeof(StatusMenuExecParam)); + smep->szProto = mir_strdup(pa->szModuleName); + + if (Proto_IsAccountLocked(pa)) + mi.flags |= CMIF_CHECKED; + + if ((mi.flags & CMIF_CHECKED) && cli.bDisplayLocked) { + mir_sntprintf(tbuf, _countof(tbuf), TranslateT("%s (locked)"), pa->tszAccountName); + mi.name.t = tbuf; + } + else mi.name.t = pa->tszAccountName; + + TMO_IntMenuItem *pimi = Menu_AddItem(hStatusMenuObject, &mi, smep); + smep->protoindex = (int)pimi; + Menu_ModifyItem(pimi, mi.name.t, mi.hIcon, mi.flags); + + cli.menuProtos = (MenuProto*)mir_realloc(cli.menuProtos, sizeof(MenuProto)*(cli.menuProtoCount + 1)); + memset(&(cli.menuProtos[cli.menuProtoCount]), 0, sizeof(MenuProto)); + cli.menuProtos[cli.menuProtoCount].pMenu = rootmenu; + cli.menuProtos[cli.menuProtoCount].szProto = mir_strdup(pa->szModuleName); + + cli.menuProtoCount++; + + char buf[256]; + mir_snprintf(buf, "RootProtocolIcon_%s", pa->szModuleName); + Menu_ConfigureItem(pimi, MCI_OPT_UNIQUENAME, buf); + + DestroyIcon(ic); + pos += 500000; + + for (int j = 0; j < _countof(statusModeList); j++) { + if (!(flags & statusModePf2List[j])) + continue; + + // adding + memset(&mi, 0, sizeof(mi)); + mi.flags = CMIF_TCHAR; + if (statusModeList[j] == ID_STATUS_OFFLINE) + mi.flags |= CMIF_CHECKED; + mi.root = rootmenu; + mi.position = pos++; + mi.name.t = cli.pfnGetStatusModeDescription(statusModeList[j], GSMDF_UNTRANSLATED); + mi.hIcon = Skin_LoadProtoIcon(pa->szModuleName, statusModeList[j]); + + // owner data + StatusMenuExecParam *smep = (StatusMenuExecParam*)mir_calloc(sizeof(StatusMenuExecParam)); + smep->custom = FALSE; + smep->status = statusModeList[j]; + smep->protoindex = i; + smep->szProto = mir_strdup(pa->szModuleName); + + hStatusMenuHandles[i].protoindex = i; + hStatusMenuHandles[i].protostatus[j] = statusModeList[j]; + hStatusMenuHandles[i].menuhandle[j] = Menu_AddItem(hStatusMenuObject, &mi, smep); + + char buf[256]; + mir_snprintf(buf, "ProtocolIcon_%s_%s", pa->szModuleName, mi.name.a); + Menu_ConfigureItem(hStatusMenuHandles[i].menuhandle[j], MCI_OPT_UNIQUENAME, buf); + + IcoLib_ReleaseIcon(mi.hIcon); + } + } + + NotifyEventHooks(cli.hPreBuildStatusMenuEvent, 0, 0); + int pos = 200000; + + // add to root menu + for (int j = 0; j < _countof(statusModeList); j++) { + for (int i = 0; i < accounts.getCount(); i++) { + PROTOACCOUNT *pa = accounts[i]; + if (!bHideStatusMenu && !cli.pfnGetProtocolVisibility(pa->szModuleName)) + continue; + + DWORD flags = pa->ppro->GetCaps(PFLAGNUM_2, 0) & ~pa->ppro->GetCaps(PFLAGNUM_5, 0); + if (!(flags & statusModePf2List[j])) + continue; + + CMenuItem mi; + mi.flags = CMIF_TCHAR; + if (statusModeList[j] == ID_STATUS_OFFLINE) + mi.flags |= CMIF_CHECKED; + + mi.hIcon = Skin_LoadIcon(skinIconStatusList[j]); + mi.position = pos++; + + // owner data + StatusMenuExecParam *smep = (StatusMenuExecParam*)mir_calloc(sizeof(StatusMenuExecParam)); + smep->status = statusModeList[j]; + { + TCHAR buf[256], hotkeyName[100]; + WORD hotKey = GetHotkeyValue(statusHotkeys[j]); + HotkeyToName(hotkeyName, _countof(hotkeyName), HIBYTE(hotKey), LOBYTE(hotKey)); + mir_sntprintf(buf, _T("%s\t%s"), cli.pfnGetStatusModeDescription(statusModeList[j], 0), hotkeyName); + mi.name.t = buf; + hStatusMainMenuHandles[j] = Menu_AddItem(hStatusMenuObject, &mi, smep); + + hStatusMainMenuHandles[j]->hotKey = hotKey; + } + + char buf[256]; + mir_snprintf(buf, "Root2ProtocolIcon_%s_%s", pa->szModuleName, mi.name.a); + Menu_ConfigureItem(hStatusMainMenuHandles[j], MCI_OPT_UNIQUENAME, buf); + + IcoLib_ReleaseIcon(mi.hIcon); + break; + } + } + + Menu_GetStatusMenu(); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static int sttRebuildHotkeys(WPARAM, LPARAM) +{ + for (int j = 0; j < _countof(statusModeList); j++) { + TCHAR buf[256], hotkeyName[100]; + WORD hotKey = GetHotkeyValue(statusHotkeys[j]); + HotkeyToName(hotkeyName, _countof(hotkeyName), HIBYTE(hotKey), LOBYTE(hotKey)); + mir_sntprintf(buf, _T("%s\t%s"), cli.pfnGetStatusModeDescription(statusModeList[j], 0), hotkeyName); + Menu_ModifyItem(hStatusMainMenuHandles[j], buf); + + hStatusMainMenuHandles[j]->hotKey = MAKELONG(HIBYTE(hotKey), LOBYTE(hotKey)); + } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +int statustopos(int status) +{ + for (int j = 0; j < _countof(statusModeList); j++) + if (status == statusModeList[j]) + return j; + + return -1; +} + +static int MenuProtoAck(WPARAM, LPARAM lParam) +{ + ACKDATA *ack = (ACKDATA*)lParam; + if (ack->type != ACKTYPE_STATUS) return 0; + if (ack->result != ACKRESULT_SUCCESS) return 0; + if (hStatusMainMenuHandles == NULL) return 0; + if (cli.pfnGetProtocolVisibility(ack->szModule) == 0) return 0; + + int overallStatus = cli.pfnGetAverageMode(NULL); + + if (overallStatus >= ID_STATUS_OFFLINE) { + int pos = statustopos(cli.currentStatusMenuItem); + if (pos == -1) + pos = 0; + + // reset all current possible checked statuses + for (int pos2 = 0; pos2 < hStatusMainMenuHandlesCnt; pos2++) + if (pos2 >= 0 && pos2 < hStatusMainMenuHandlesCnt) + Menu_ModifyItem(hStatusMainMenuHandles[pos2], NULL, INVALID_HANDLE_VALUE, 0); + + cli.currentStatusMenuItem = overallStatus; + pos = statustopos(cli.currentStatusMenuItem); + if (pos >= 0 && pos < hStatusMainMenuHandlesCnt) + Menu_SetChecked(hStatusMainMenuHandles[pos], true); + } + else { + int pos = statustopos(cli.currentStatusMenuItem); + if (pos == -1) + pos = 0; + + if (pos >= 0 && pos < hStatusMainMenuHandlesCnt) + Menu_ModifyItem(hStatusMainMenuHandles[pos], NULL, INVALID_HANDLE_VALUE, 0); + + cli.currentStatusMenuItem = 0; + } + + for (int i = 0; i < accounts.getCount(); i++) { + if (!mir_strcmp(accounts[i]->szModuleName, ack->szModule)) { + if (((int)ack->hProcess >= ID_STATUS_OFFLINE || (int)ack->hProcess == 0) && (int)ack->hProcess < ID_STATUS_OFFLINE + _countof(statusModeList)) { + int pos = statustopos((int)ack->hProcess); + if (pos == -1) + pos = 0; + for (pos = 0; pos < _countof(statusModeList); pos++) + Menu_ModifyItem(hStatusMenuHandles[i].menuhandle[pos], NULL, INVALID_HANDLE_VALUE, 0); + } + + if (ack->lParam >= ID_STATUS_OFFLINE && ack->lParam < ID_STATUS_OFFLINE + _countof(statusModeList)) { + int pos = statustopos((int)ack->lParam); + if (pos >= 0 && pos < _countof(statusModeList)) + Menu_SetChecked(hStatusMenuHandles[i].menuhandle[pos], true); + } + break; + } + } + + //BuildStatusMenu(0, 0); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static MenuProto* FindProtocolMenu(const char *proto) +{ + for (int i = 0; i < cli.menuProtoCount; i++) + if (cli.menuProtos[i].pMenu && !mir_strcmpi(cli.menuProtos[i].szProto, proto)) + return &cli.menuProtos[i]; + + if (cli.menuProtoCount == 1) + if (!mir_strcmpi(cli.menuProtos[0].szProto, proto)) + return &cli.menuProtos[0]; + + return NULL; +} + +HGENMENU fnGetProtocolMenu(const char* proto) +{ + MenuProto *mp = FindProtocolMenu(proto); + return (mp) ? mp->pMenu : NULL; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static INT_PTR HotkeySetStatus(WPARAM, LPARAM lParam) +{ + return SetStatusMode(lParam, 0); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// PROTOCOL MENU + +MIR_APP_DLL(HGENMENU) Menu_AddProtoMenuItem(TMO_MenuItem *mi, const char *pszProto) +{ + if (mi == NULL) + return NULL; + + if (db_get_b(NULL, "CList", "MoveProtoMenus", TRUE)) + return Menu_AddStatusMenuItem(mi, pszProto); + + char szService[100]; + if (pszProto && mi->pszService && *mi->pszService == '/') { + strncpy_s(szService, pszProto, _TRUNCATE); + strncat_s(szService, mi->pszService, _TRUNCATE); + mi->pszService = szService; + } + return Menu_AddMainMenuItem(mi); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void InitCustomMenus(void) +{ + CreateServiceFunction("MainMenuExecService", MainMenuExecService); + + CreateServiceFunction("ContactMenuExecService", ContactMenuExecService); + CreateServiceFunction("ContactMenuCheckService", ContactMenuCheckService); + + CreateServiceFunction("StatusMenuExecService", StatusMenuExecService); + CreateServiceFunction("StatusMenuCheckService", StatusMenuCheckService); + + // free services + CreateServiceFunction("CLISTMENUS/FreeOwnerDataMainMenu", FreeOwnerDataMainMenu); + CreateServiceFunction("CLISTMENUS/FreeOwnerDataContactMenu", FreeOwnerDataContactMenu); + CreateServiceFunction("CLISTMENUS/FreeOwnerDataStatusMenu", FreeOwnerDataStatusMenu); + + CreateServiceFunction(MS_CLIST_SETSTATUSMODE, SetStatusMode); + + CreateServiceFunction(MS_CLIST_MENUPROCESSCOMMAND, MenuProcessCommand); + CreateServiceFunction(MS_CLIST_MENUPROCESSHOTKEY, MenuProcessHotkey); + + hPreBuildContactMenuEvent = CreateHookableEvent(ME_CLIST_PREBUILDCONTACTMENU); + hPreBuildMainMenuEvent = CreateHookableEvent(ME_CLIST_PREBUILDMAINMENU); + cli.hPreBuildStatusMenuEvent = CreateHookableEvent(ME_CLIST_PREBUILDSTATUSMENU); + hStatusModeChangeEvent = CreateHookableEvent(ME_CLIST_STATUSMODECHANGE); + + HookEvent(ME_PROTO_ACK, MenuProtoAck); + + hMainMenu = CreatePopupMenu(); + hStatusMenu = CreatePopupMenu(); + + hStatusMainMenuHandles = NULL; + hStatusMainMenuHandlesCnt = 0; + + hStatusMenuHandles = NULL; + hStatusMenuHandlesCnt = 0; + + // new menu sys + InitGenMenu(); + + // main menu + hMainMenuObject = Menu_AddObject("MainMenu", LPGEN("Main menu"), 0, "MainMenuExecService"); + Menu_ConfigureObject(hMainMenuObject, MCO_OPT_USERDEFINEDITEMS, TRUE); + Menu_ConfigureObject(hMainMenuObject, MCO_OPT_FREE_SERVICE, (INT_PTR)"CLISTMENUS/FreeOwnerDataMainMenu"); + + // contact menu + hContactMenuObject = Menu_AddObject("ContactMenu", LPGEN("Contact menu"), "ContactMenuCheckService", "ContactMenuExecService"); + Menu_ConfigureObject(hContactMenuObject, MCO_OPT_USERDEFINEDITEMS, TRUE); + Menu_ConfigureObject(hContactMenuObject, MCO_OPT_FREE_SERVICE, (INT_PTR)"CLISTMENUS/FreeOwnerDataContactMenu"); + + // other menus + InitGroupMenus(); + InitFramesMenus(); + InitTrayMenus(); + + // initialize hotkeys + CreateServiceFunction(MS_CLIST_HKSTATUS, HotkeySetStatus); + + HOTKEYDESC hkd = { sizeof(hkd) }; + hkd.ptszSection = _T("Status"); + hkd.dwFlags = HKD_TCHAR; + for (int i = 0; i < _countof(statusHotkeys); i++) { + char szName[30]; + mir_snprintf(szName, _countof(szName), "StatusHotKey_%d", i); + hkd.pszName = szName; + hkd.lParam = statusModeList[i]; + hkd.ptszDescription = fnGetStatusModeDescription(hkd.lParam, 0); + hkd.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL, '0' + i) | HKF_MIRANDA_LOCAL; + hkd.pszService = MS_CLIST_HKSTATUS; + statusHotkeys[i] = Hotkey_Register(&hkd); + } + + HookEvent(ME_HOTKEYS_CHANGED, sttRebuildHotkeys); + + // add exit command to menu + CMenuItem mi; + mi.position = 0x7fffffff; + mi.pszService = "CloseAction"; + mi.name.a = LPGEN("E&xit"); + mi.hIcolibItem = Skin_GetIconHandle(SKINICON_OTHER_EXIT); + Menu_AddMainMenuItem(&mi); + + cli.currentStatusMenuItem = ID_STATUS_OFFLINE; + cli.currentDesiredStatusMode = ID_STATUS_OFFLINE; + + HookEvent(ME_SKIN_ICONSCHANGED, MenuIconsChanged); +} + +void UninitCustomMenus(void) +{ + mir_free(hStatusMainMenuHandles); + hStatusMainMenuHandles = NULL; + + mir_free(hStatusMenuHandles); + hStatusMenuHandles = NULL; + + Menu_RemoveObject(hMainMenuObject); + Menu_RemoveObject(hMainMenuObject); + + UnloadMoveToGroup(); + FreeMenuProtos(); + + DestroyMenu(hMainMenu); + DestroyMenu(hStatusMenu); +} diff --git a/src/mir_app/src/menu_frames.cpp b/src/mir_app/src/menu_frames.cpp new file mode 100644 index 0000000000..7c76e7d371 --- /dev/null +++ b/src/mir_app/src/menu_frames.cpp @@ -0,0 +1,113 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (ñ) 2012-15 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "stdafx.h" + +#include +#include "genmenu.h" + +static int hFrameMenuObject; +static HANDLE hPreBuildFrameMenuEvent; + +///////////////////////////////////////////////////////////////////////////////////////// +// contactmenu exec param(ownerdata) +// also used in checkservice + +struct FrameMenuExecParam +{ + ptrA szServiceName; +}; + +INT_PTR FreeOwnerDataFrameMenu(WPARAM, LPARAM lParam) +{ + delete (FrameMenuExecParam*)lParam; + return 0; +} + +static INT_PTR AddContextFrameMenuItem(WPARAM, LPARAM lParam) +{ + TMO_MenuItem *pmi = (TMO_MenuItem*)lParam; + + FrameMenuExecParam *fmep = new FrameMenuExecParam(); + fmep->szServiceName = mir_strdup(pmi->pszService); + return (INT_PTR)Menu_AddItem(hFrameMenuObject, pmi, fmep); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// called with: +// wparam - ownerdata +// lparam - lparam from winproc + +INT_PTR FrameMenuExecService(WPARAM wParam, LPARAM lParam) +{ + FrameMenuExecParam *fmep = (FrameMenuExecParam*)wParam; + if (fmep == NULL) + return -1; + + CallService(fmep->szServiceName, lParam, 0); + return 0; +} + +INT_PTR FrameMenuCheckService(WPARAM wParam, LPARAM) +{ + TCheckProcParam *pcpp = (TCheckProcParam*)wParam; + if (pcpp == NULL) + return FALSE; + + TMO_IntMenuItem *pimi = pcpp->MenuItemHandle; + return pimi->execParam == pcpp->wParam || pimi->execParam == -1; +} + +static INT_PTR ContextFrameMenuNotify(WPARAM wParam, LPARAM lParam) +{ + NotifyEventHooks(hPreBuildFrameMenuEvent, wParam, lParam); + return 0; +} + +static INT_PTR BuildContextFrameMenu(WPARAM wParam, LPARAM lParam) +{ + ContextFrameMenuNotify(wParam, -1); + + HMENU hMenu = CreatePopupMenu(); + Menu_Build(hMenu, hFrameMenuObject, wParam, lParam); + return (INT_PTR)hMenu; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void InitFramesMenus(void) +{ + CreateServiceFunction("FrameMenuExecService", FrameMenuExecService); + CreateServiceFunction("FrameMenuCheckService", FrameMenuCheckService); + CreateServiceFunction("FrameMenuFreeService", FreeOwnerDataFrameMenu); + + CreateServiceFunction("CList/AddContextFrameMenuItem", AddContextFrameMenuItem); + CreateServiceFunction(MS_CLIST_MENUBUILDFRAMECONTEXT, BuildContextFrameMenu); + CreateServiceFunction(MS_CLIST_FRAMEMENUNOTIFY, ContextFrameMenuNotify); + hPreBuildFrameMenuEvent = CreateHookableEvent(ME_CLIST_PREBUILDFRAMEMENU); + + // frame menu object + hFrameMenuObject = Menu_AddObject("FrameMenu", LPGEN("Frame menu"), "FrameMenuCheckService", "FrameMenuExecService"); + Menu_ConfigureObject(hFrameMenuObject, MCO_OPT_FREE_SERVICE, "FrameMenuFreeService"); +} diff --git a/src/mir_app/src/menu_groups.cpp b/src/mir_app/src/menu_groups.cpp new file mode 100644 index 0000000000..ea7c929ee5 --- /dev/null +++ b/src/mir_app/src/menu_groups.cpp @@ -0,0 +1,250 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (ñ) 2012-15 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-08 Miranda ICQ/IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "stdafx.h" + +///////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////// Group MENU ////////////////////////////// + +int hGroupMenuObject, hSubGroupMenuObject; +static HANDLE hEventPreBuildGroupMenu, hEventPreBuildSubGroupMenu; + +// Groupmenu exec param(ownerdata) + +struct GroupMenuExecParam +{ + char *szServiceName; + int Param1, Param2; +}; + +MIR_APP_DLL(HMENU) Menu_BuildGroupMenu() +{ + NotifyEventHooks(hEventPreBuildGroupMenu, 0, 0); + + HMENU hMenu = CreatePopupMenu(); + Menu_Build(hMenu, hGroupMenuObject); + return hMenu; +} + +MIR_APP_DLL(HGENMENU) Menu_AddGroupMenuItem(TMO_MenuItem *pmi, GroupMenuParam *gmp) +{ + GroupMenuExecParam *mmep = (GroupMenuExecParam*)mir_calloc(sizeof(GroupMenuExecParam)); + if (mmep == NULL) + return 0; + + // we need just one parametr. + mmep->szServiceName = mir_strdup(pmi->pszService); + if (gmp != NULL) { + mmep->Param1 = gmp->wParam; + mmep->Param2 = gmp->lParam; + } + + HGENMENU hNewItem = Menu_AddItem(hGroupMenuObject, pmi, mmep); + + char buf[1024]; + mir_snprintf(buf, "%s/%s", pmi->pszService, pmi->name.a); + Menu_ConfigureItem(hNewItem, MCI_OPT_UNIQUENAME, buf); + return hNewItem; +} + +// called with: +// wparam - ownerdata +// lparam - lparam from winproc +INT_PTR GroupMenuExecService(WPARAM wParam, LPARAM lParam) +{ + if (wParam != 0) { + GroupMenuExecParam * mmep = (GroupMenuExecParam *)wParam; + if (!mir_strcmp(mmep->szServiceName, "Help/AboutCommand")) { + //bug in help.c,it used wparam as parent window handle without reason. + mmep->Param1 = 0; + CallService(mmep->szServiceName, mmep->Param1, lParam); + } + else CallService(mmep->szServiceName, mmep->Param1, mmep->Param2); + } + return 1; +} + +INT_PTR FreeOwnerDataGroupMenu(WPARAM, LPARAM lParam) +{ + GroupMenuExecParam * mmep = (GroupMenuExecParam *)lParam; + if (mmep != NULL) { + mir_free(mmep->szServiceName); + mir_free(mmep); + } + + return 0; +} + +INT_PTR HideGroupsHelper(WPARAM, LPARAM) +{ + int newVal = !(GetWindowLongPtr(cli.hwndContactTree, GWL_STYLE) & CLS_HIDEEMPTYGROUPS); + db_set_b(NULL, "CList", "HideEmptyGroups", (BYTE)newVal); + SendMessage(cli.hwndContactTree, CLM_SETHIDEEMPTYGROUPS, newVal, 0); + return 0; +} + +INT_PTR UseGroupsHelper(WPARAM, LPARAM) +{ + int newVal = !(GetWindowLongPtr(cli.hwndContactTree, GWL_STYLE) & CLS_USEGROUPS); + db_set_b(NULL, "CList", "UseGroups", (BYTE)newVal); + SendMessage(cli.hwndContactTree, CLM_SETUSEGROUPS, newVal,0); + return 0; +} + +INT_PTR HideOfflineRootHelper(WPARAM, LPARAM) +{ + SendMessage(cli.hwndContactTree, CLM_SETHIDEOFFLINEROOT, + !SendMessage(cli.hwndContactTree, CLM_GETHIDEOFFLINEROOT, 0, 0), + 0); + return 0; +} + +INT_PTR CreateGroupHelper(WPARAM, LPARAM) +{ + SendMessage(cli.hwndContactTree, CLM_SETHIDEEMPTYGROUPS, 0, 0); + SendMessage(cli.hwndContactTree, CLM_SETUSEGROUPS, 1, 0); + Clist_CreateGroup(0, 0); + return 0; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////// SubGroup MENU ////////////////////////////// + +struct SubGroupMenuExecParam +{ + char *szServiceName; + int Param1, Param2; +}; + +MIR_APP_DLL(HMENU) Menu_BuildSubGroupMenu(ClcGroup *group) +{ + NotifyEventHooks(hEventPreBuildSubGroupMenu, (WPARAM)group, 0); + + HMENU hMenu = CreatePopupMenu(); + Menu_Build(hMenu, hSubGroupMenuObject, (WPARAM)group, 0); + return hMenu; +} + +HMENU cliBuildGroupPopupMenu(ClcGroup *group) +{ + return Menu_BuildSubGroupMenu(group); +} + +MIR_APP_DLL(HGENMENU) Menu_AddSubGroupMenuItem(TMO_MenuItem *pmi, GroupMenuParam *gmp) +{ + SubGroupMenuExecParam *mmep = (SubGroupMenuExecParam*)mir_calloc(sizeof(SubGroupMenuExecParam)); + if (mmep == NULL) + return 0; + + // we need just one parametr. + mmep->szServiceName = mir_strdup(pmi->pszService); + if (gmp != NULL) { + mmep->Param1 = gmp->wParam; + mmep->Param2 = gmp->lParam; + } + + HGENMENU hNewItem = Menu_AddItem(hSubGroupMenuObject, pmi, mmep); + + char buf[1024]; + mir_snprintf(buf, "%s/%s", pmi->pszService, pmi->name.a); + Menu_ConfigureItem(hNewItem, MCI_OPT_UNIQUENAME, buf); + return hNewItem; +} + +static INT_PTR SubGroupMenuCheckService(WPARAM wParam, LPARAM) +{ + TCheckProcParam * CParam = (TCheckProcParam*)wParam; + if (CParam) { + SubGroupMenuExecParam * mmep = (SubGroupMenuExecParam *)(CParam->MenuItemOwnerData); + if (mmep) + mmep->Param2 = CParam->lParam; + } + return 1; +} + +// called with: +// wparam - ownerdata +// lparam - lparam from winproc +static INT_PTR SubGroupMenuExecService(WPARAM wParam, LPARAM lParam) +{ + if (wParam != 0) { + SubGroupMenuExecParam * mmep = (SubGroupMenuExecParam *)wParam; + if (!mir_strcmp(mmep->szServiceName, "Help/AboutCommand")) { + //bug in help.c,it used wparam as parent window handle without reason. + mmep->Param1 = 0; + CallService(mmep->szServiceName, mmep->Param1, lParam); + } + else CallService(mmep->szServiceName, mmep->Param1, lParam); + } + return 1; +} + +static INT_PTR FreeOwnerDataSubGroupMenu(WPARAM, LPARAM lParam) +{ + SubGroupMenuExecParam * mmep = (SubGroupMenuExecParam *)lParam; + if (mmep != NULL) { + mir_free(mmep->szServiceName); + mir_free(mmep); + } + return 0; +} + +// wparam menu handle to pass to clc.c +// lparam WM_COMMAND HWND +static INT_PTR GroupMenuExecProxy(WPARAM wParam, LPARAM lParam) +{ + SendMessage(lParam ? (HWND)lParam : (HWND)cli.hwndContactTree, WM_COMMAND, wParam, 0); + return 0; +} + +void InitGroupMenus(void) +{ + // Group menu + CreateServiceFunction("CLISTMENUSGroup/ExecService", GroupMenuExecService); + CreateServiceFunction("CLISTMENUSGroup/FreeOwnerDataGroupMenu", FreeOwnerDataGroupMenu); + CreateServiceFunction("CLISTMENUSGroup/HideGroupsHelper", HideGroupsHelper); + CreateServiceFunction("CLISTMENUSGroup/UseGroupsHelper", UseGroupsHelper); + CreateServiceFunction("CLISTMENUSGroup/HideOfflineRootHelper", HideOfflineRootHelper); + CreateServiceFunction("CLISTMENUSGroup/CreateGroupHelper", CreateGroupHelper); + + hEventPreBuildGroupMenu = CreateHookableEvent(ME_CLIST_PREBUILDGROUPMENU); + + hGroupMenuObject = Menu_AddObject("GroupMenu", LPGEN("Group menu"), 0, "CLISTMENUSGroup/ExecService"); + Menu_ConfigureObject(hGroupMenuObject, MCO_OPT_USERDEFINEDITEMS, TRUE); + Menu_ConfigureObject(hGroupMenuObject, MCO_OPT_FREE_SERVICE, "CLISTMENUSGroup/FreeOwnerDataGroupMenu"); + Menu_ConfigureObject(hGroupMenuObject, MCO_OPT_ONADD_SERVICE, "CLISTMENUSGroup/GroupMenuOnAddService"); + + // SubGroup menu + CreateServiceFunction("CLISTMENUSSubGroup/ExecService", SubGroupMenuExecService); + CreateServiceFunction("CLISTMENUSSubGroup/FreeOwnerDataSubGroupMenu", FreeOwnerDataSubGroupMenu); + CreateServiceFunction("CLISTMENUSSubGroup/SubGroupMenuCheckService", SubGroupMenuCheckService); + CreateServiceFunction("CLISTMENUSSubGroup/GroupMenuExecProxy", GroupMenuExecProxy); + + hEventPreBuildSubGroupMenu = CreateHookableEvent(ME_CLIST_PREBUILDSUBGROUPMENU); + + hSubGroupMenuObject = Menu_AddObject("SubGroupMenu", LPGEN("Subgroup menu"), 0, "CLISTMENUSSubGroup/ExecService"); + Menu_ConfigureObject(hSubGroupMenuObject, MCO_OPT_USERDEFINEDITEMS, TRUE); + Menu_ConfigureObject(hSubGroupMenuObject, MCO_OPT_FREE_SERVICE, "CLISTMENUSSubGroup/FreeOwnerDataSubGroupMenu"); + Menu_ConfigureObject(hSubGroupMenuObject, MCO_OPT_CHECK_SERVICE, "CLISTMENUSSubGroup/SubGroupMenuCheckService"); +} diff --git a/src/mir_app/src/menu_options.cpp b/src/mir_app/src/menu_options.cpp new file mode 100644 index 0000000000..6e57e67f9d --- /dev/null +++ b/src/mir_app/src/menu_options.cpp @@ -0,0 +1,501 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (ñ) 2012-15 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "stdafx.h" +#include "genmenu.h" + +#define STR_SEPARATOR _T("-----------------------------------") + +extern bool bIconsDisabled; +extern int DefaultImageListColorDepth; +void RebuildProtoMenus(); + +///////////////////////////////////////////////////////////////////////////////////////// + +struct MenuItemOptData : public MZeroedObject +{ + ~MenuItemOptData() {} + + int pos; + + ptrT name; + ptrT defname; + ptrA uniqname; + + bool bShow; + int id; + + TMO_IntMenuItem *pimi; +}; + +static int SortMenuItems(const MenuItemOptData *p1, const MenuItemOptData *p2) +{ + if (p1->pos < p2->pos) return -1; + if (p1->pos > p2->pos) return 1; + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +class CGenMenuOptionsPage : public CDlgBase +{ + int iInitMenuValue; + bool bRebuild; + + void SaveTree() + { + int MenuObjectId; + if (!GetCurrentMenuObjectID(MenuObjectId)) + return; + + TCHAR idstr[100]; + + TVITEMEX tvi; + tvi.hItem = m_menuItems.GetRoot(); + tvi.cchTextMax = _countof(idstr); + tvi.mask = TVIF_TEXT | TVIF_PARAM | TVIF_HANDLE | TVIF_IMAGE; + tvi.pszText = idstr; + + int count = 0; + TIntMenuObject *pmo = GetMenuObjbyId(MenuObjectId); + if (pmo == NULL) + return; + + char MenuNameItems[256]; + mir_snprintf(MenuNameItems, _countof(MenuNameItems), "%s_Items", pmo->pszName); + int runtimepos = 100; + + while (tvi.hItem != NULL) { + m_menuItems.GetItem(&tvi); + MenuItemOptData *iod = (MenuItemOptData*)tvi.lParam; + if (iod->pimi) { + char menuItemName[256], DBString[300]; + GetMenuItemName(iod->pimi, menuItemName, sizeof(menuItemName)); + + mir_snprintf(DBString, _countof(DBString), "%s_visible", menuItemName); + db_set_b(NULL, MenuNameItems, DBString, tvi.iImage != 0); + + mir_snprintf(DBString, _countof(DBString), "%s_pos", menuItemName); + db_set_dw(NULL, MenuNameItems, DBString, runtimepos); + + mir_snprintf(DBString, _countof(DBString), "%s_name", menuItemName); + if (iod->name != NULL && iod->defname != NULL && + mir_tstrcmp(iod->name, iod->defname) != 0) + db_set_ts(NULL, MenuNameItems, DBString, iod->name); + else + db_unset(NULL, MenuNameItems, DBString); + + runtimepos += 100; + } + + if (iod->name && !mir_tstrcmp(iod->name, STR_SEPARATOR) && tvi.iImage) + runtimepos += SEPARATORPOSITIONINTERVAL; + + tvi.hItem = m_menuItems.GetNextSibling(tvi.hItem); + count++; + } + } + + void FreeTreeData() + { + HTREEITEM hItem = m_menuItems.GetRoot(); + while (hItem != NULL) { + TVITEMEX tvi; + tvi.mask = TVIF_HANDLE | TVIF_PARAM; + tvi.hItem = hItem; + m_menuItems.GetItem(&tvi); + delete (MenuItemOptData *)tvi.lParam; + + tvi.lParam = 0; + m_menuItems.SetItem(&tvi); + + hItem = m_menuItems.GetNextSibling(hItem); + } + } + + void RebuildCurrent() + { + int MenuObjectID; + if (GetCurrentMenuObjectID(MenuObjectID)) + BuildTree(MenuObjectID, true); + } + + void BuildTreeInternal(const char *pszModule, bool bReread, HGENMENU pFirst, HTREEITEM hRoot) + { + LIST arItems(10, SortMenuItems); + + for (TMO_IntMenuItem *p = pFirst; p != NULL; p = p->next) { + // filter out items whose presence & position might not be changed + if (p->mi.flags & CMIF_SYSTEM) + continue; + + char menuItemName[256]; + GetMenuItemName(p, menuItemName, _countof(menuItemName)); + + MenuItemOptData *PD = new MenuItemOptData(); + + char buf[256]; + mir_snprintf(buf, "%s_name", menuItemName); + ptrT tszName(db_get_tsa(NULL, pszModule, buf)); + if (tszName != 0) + PD->name = tszName.detach(); + else + PD->name = mir_tstrdup(GetMenuItemText(p)); + + PD->pimi = p; + PD->defname = mir_tstrdup(GetMenuItemText(p)); + + mir_snprintf(buf, "%s_visible", menuItemName); + PD->bShow = db_get_b(NULL, pszModule, buf, 1) != 0; + + if (bReread) { + mir_snprintf(buf, "%s_pos", menuItemName); + PD->pos = db_get_dw(NULL, pszModule, buf, 1); + } + else PD->pos = (PD->pimi) ? PD->pimi->originalPosition : 0; + + PD->id = p->iCommand; + + if (p->UniqName) + PD->uniqname = mir_strdup(p->UniqName); + + arItems.insert(PD); + } + + int lastpos = 0; + bool bIsFirst = TRUE; + + TVINSERTSTRUCT tvis; + tvis.hParent = hRoot; + tvis.hInsertAfter = TVI_LAST; + tvis.item.mask = TVIF_PARAM | TVIF_CHILDREN | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE; + + for (int i = 0; i < arItems.getCount(); i++) { + MenuItemOptData *PD = arItems[i]; + if (PD->pos - lastpos >= SEPARATORPOSITIONINTERVAL) { + MenuItemOptData *sep = new MenuItemOptData(); + sep->id = -1; + sep->name = mir_tstrdup(STR_SEPARATOR); + sep->pos = PD->pos - 1; + + tvis.item.lParam = (LPARAM)sep; + tvis.item.pszText = sep->name; + tvis.item.iImage = tvis.item.iSelectedImage = 1; + tvis.item.cChildren = 0; + m_menuItems.InsertItem(&tvis); + } + + tvis.item.lParam = (LPARAM)PD; + tvis.item.pszText = PD->name; + tvis.item.iImage = tvis.item.iSelectedImage = PD->bShow; + tvis.item.cChildren = PD->pimi->submenu.first != NULL; + + HTREEITEM hti = m_menuItems.InsertItem(&tvis); + if (bIsFirst) { + if (hRoot == NULL) + m_menuItems.SelectItem(hti); + bIsFirst = false; + } + + if (PD->pimi->submenu.first != NULL) { + BuildTreeInternal(pszModule, bReread, PD->pimi->submenu.first, hti); + m_menuItems.Expand(hti, TVE_EXPAND); + } + + lastpos = PD->pos; + } + } + + bool BuildTree(int MenuObjectId, bool bReread) + { + FreeTreeData(); + + TIntMenuObject *pmo = GetMenuObjbyId(MenuObjectId); + if (pmo == NULL || pmo->m_items.first == NULL) + return false; + + char MenuNameItems[256]; + mir_snprintf(MenuNameItems, _countof(MenuNameItems), "%s_Items", pmo->pszName); + + bRebuild = true; + m_menuItems.SendMsg(WM_SETREDRAW, FALSE, 0); + m_menuItems.DeleteAllItems(); + + BuildTreeInternal(MenuNameItems, bReread, pmo->m_items.first, NULL); + + m_menuItems.SendMsg(WM_SETREDRAW, TRUE, 0); + bRebuild = false; + + ShowWindow(m_warning.GetHwnd(), (pmo->m_bUseUserDefinedItems) ? SW_HIDE : SW_SHOW); + m_menuItems.Enable(pmo->m_bUseUserDefinedItems); + m_btnInsert.Enable(pmo->m_bUseUserDefinedItems); + return 1; + } + + bool GetCurrentMenuObjectID(int &result) + { + int iItem = m_menuObjects.GetCurSel(); + if (iItem == -1) + return false; + + result = (int)m_menuObjects.GetItemData(iItem); + return true; + } + + CCtrlListBox m_menuObjects; + CCtrlTreeView m_menuItems; + CCtrlCheck m_radio1, m_radio2, m_enableIcons; + CCtrlEdit m_customName, m_service; + CCtrlButton m_btnInsert, m_btnReset, m_btnSet, m_btnDefault; + CCtrlBase m_warning; + +public: + CGenMenuOptionsPage() : + CDlgBase(g_hInst, IDD_OPT_GENMENU), + m_menuItems(this, IDC_MENUITEMS), + m_menuObjects(this, IDC_MENUOBJECTS), + m_radio1(this, IDC_RADIO1), + m_radio2(this, IDC_RADIO2), + m_enableIcons(this, IDC_DISABLEMENUICONS), + m_btnInsert(this, IDC_INSERTSEPARATOR), + m_btnReset(this, IDC_RESETMENU), + m_btnSet(this, IDC_GENMENU_SET), + m_btnDefault(this, IDC_GENMENU_DEFAULT), + m_customName(this, IDC_GENMENU_CUSTOMNAME), + m_service(this, IDC_GENMENU_SERVICE), + m_warning(this, IDC_NOTSUPPORTWARNING), + bRebuild(false) + { + m_btnSet.OnClick = Callback(this, &CGenMenuOptionsPage::btnSet_Clicked); + m_btnReset.OnClick = Callback(this, &CGenMenuOptionsPage::btnReset_Clicked); + m_btnInsert.OnClick = Callback(this, &CGenMenuOptionsPage::btnInsert_Clicked); + m_btnDefault.OnClick = Callback(this, &CGenMenuOptionsPage::btnDefault_Clicked); + + m_menuObjects.OnSelChange = Callback(this, &CGenMenuOptionsPage::onMenuObjectChanged); + + m_menuItems.SetFlags(MTREE_CHECKBOX | MTREE_DND | MTREE_MULTISELECT); + m_menuItems.OnSelChanged = Callback(this, &CGenMenuOptionsPage::onMenuItemChanged); + m_menuItems.OnBeginDrag = Callback(this, &CGenMenuOptionsPage::onMenuItemDrag); + + m_customName.SetSilent(); + m_service.SetSilent(); + } + + //---- init dialog ------------------------------------------- + virtual void OnInitDialog() + { + iInitMenuValue = db_get_b(NULL, "CList", "MoveProtoMenus", TRUE); + + HIMAGELIST himlCheckBoxes = ImageList_Create(g_iIconSX, g_iIconSY, ILC_COLOR32 | ILC_MASK, 2, 2); + ImageList_AddIcon_IconLibLoaded(himlCheckBoxes, SKINICON_OTHER_NOTICK); + ImageList_AddIcon_IconLibLoaded(himlCheckBoxes, SKINICON_OTHER_TICK); + m_menuItems.SetImageList(himlCheckBoxes, TVSIL_NORMAL); + + if (iInitMenuValue) + m_radio2.SetState(true); + else + m_radio1.SetState(true); + + m_enableIcons.SetState(!bIconsDisabled); + + //---- init menu object list -------------------------------------- + for (int i = 0; i < g_menus.getCount(); i++) { + TIntMenuObject *p = g_menus[i]; + if (p->id != (int)hStatusMenuObject && p->m_bUseUserDefinedItems) + m_menuObjects.AddString(TranslateTS(p->ptszDisplayName), p->id); + } + + m_menuObjects.SetCurSel(0); + RebuildCurrent(); + } + + virtual void OnApply() + { + bIconsDisabled = m_enableIcons.GetState() == 0; + db_set_b(NULL, "CList", "DisableMenuIcons", bIconsDisabled); + SaveTree(); + + int iNewMenuValue = !m_radio1.GetState(); + if (iNewMenuValue != iInitMenuValue) { + db_set_b(NULL, "CList", "MoveProtoMenus", iNewMenuValue); + + RebuildProtoMenus(); + iInitMenuValue = iNewMenuValue; + } + RebuildCurrent(); + } + + virtual void OnDestroy() + { + ImageList_Destroy(m_menuItems.GetImageList(TVSIL_NORMAL)); + FreeTreeData(); + } + + void btnInsert_Clicked(CCtrlButton*) + { + HTREEITEM hti = m_menuItems.GetSelection(); + if (hti == NULL) + return; + + TVITEMEX tvi = { 0 }; + tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM | TVIF_TEXT; + tvi.hItem = hti; + if (!m_menuItems.GetItem(&tvi)) + return; + + MenuItemOptData *PD = new MenuItemOptData(); + PD->id = -1; + PD->name = mir_tstrdup(STR_SEPARATOR); + PD->pos = ((MenuItemOptData *)tvi.lParam)->pos - 1; + + TVINSERTSTRUCT tvis = { 0 }; + tvis.item.lParam = (LPARAM)PD; + tvis.item.pszText = PD->name; + tvis.item.iImage = tvis.item.iSelectedImage = 1; + tvis.hInsertAfter = hti; + tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE; + m_menuItems.InsertItem(&tvis); + + NotifyChange(); + } + + void btnReset_Clicked(CCtrlButton*) + { + int MenuObjectID; + if (GetCurrentMenuObjectID(MenuObjectID)) { + BuildTree(MenuObjectID, false); + NotifyChange(); + } + } + + void btnDefault_Clicked(CCtrlButton*) + { + HTREEITEM hti = m_menuItems.GetSelection(); + if (hti == NULL) + return; + + TVITEMEX tvi; + tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM; + tvi.hItem = hti; + m_menuItems.GetItem(&tvi); + + MenuItemOptData *iod = (MenuItemOptData *)tvi.lParam; + if (iod->name && _tcsstr(iod->name, STR_SEPARATOR)) + return; + + iod->name = mir_tstrdup(iod->defname); + + SaveTree(); + RebuildCurrent(); + NotifyChange(); + } + + void btnSet_Clicked(CCtrlButton*) + { + HTREEITEM hti = m_menuItems.GetSelection(); + if (hti == NULL) + return; + + TVITEMEX tvi; + tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM; + tvi.hItem = hti; + m_menuItems.GetItem(&tvi); + + MenuItemOptData *iod = (MenuItemOptData *)tvi.lParam; + if (iod->name && _tcsstr(iod->name, STR_SEPARATOR)) + return; + + iod->name = m_customName.GetText(); + + SaveTree(); + RebuildCurrent(); + NotifyChange(); + } + + void onMenuObjectChanged(void*) + { + m_initialized = false; + RebuildCurrent(); + m_initialized = true; + } + + void onMenuItemChanged(void*) + { + if (bRebuild) + return; + + m_customName.SetTextA(""); + m_service.SetTextA(""); + + m_btnDefault.Enable(false); + m_btnSet.Enable(false); + m_customName.Enable(false); + + HTREEITEM hti = m_menuItems.GetSelection(); + if (hti == NULL) + return; + + TVITEMEX tvi; + tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM; + tvi.hItem = hti; + m_menuItems.GetItem(&tvi); + if (tvi.lParam == 0) + return; + + MenuItemOptData *iod = (MenuItemOptData *)tvi.lParam; + if (iod->name && _tcsstr(iod->name, STR_SEPARATOR)) + return; + + m_customName.SetText(iod->name); + + if (iod->pimi->submenu.first == NULL && iod->uniqname) + m_service.SetTextA(iod->uniqname); + + m_btnDefault.Enable(mir_tstrcmp(iod->name, iod->defname) != 0); + m_btnSet.Enable(true); + m_customName.Enable(true); + } + + void onMenuItemDrag(CCtrlTreeView::TEventInfo *evt) + { + MenuItemOptData *p = (MenuItemOptData*)evt->nmtv->itemNew.lParam; + if (p->pimi == NULL) + evt->nmhdr->code = 0; // reject an attempt to move a separator + else if (p->pimi->mi.flags & CMIF_UNMOVABLE) + evt->nmhdr->code = 0; // reject an attempt to change item's position + } +}; + +int GenMenuOptInit(WPARAM wParam, LPARAM) +{ + OPTIONSDIALOGPAGE odp = { 0 }; + odp.position = -1000000000; + odp.pszTitle = LPGEN("Menus"); + odp.pszGroup = LPGEN("Customize"); + odp.flags = ODPF_BOLDGROUPS; + odp.pDialog = new CGenMenuOptionsPage(); + Options_AddPage(wParam, &odp); + + return ProtocolOrderOptInit(wParam, 0); +} diff --git a/src/mir_app/src/menu_tray.cpp b/src/mir_app/src/menu_tray.cpp new file mode 100644 index 0000000000..f3ccede108 --- /dev/null +++ b/src/mir_app/src/menu_tray.cpp @@ -0,0 +1,80 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (ñ) 2012-15 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "stdafx.h" + +#include "genmenu.h" + +static int hTrayMenuObject; +static HANDLE hEventPreBuildTrayMenu; + +///////////////////////////////////////////////////////////////////////////////////////// +// Tray menu services + +MIR_APP_DLL(HMENU) Menu_BuildTrayMenu(void) +{ + NotifyEventHooks(hEventPreBuildTrayMenu, 0, 0); + + HMENU hMenu = CreatePopupMenu(); + Menu_Build(hMenu, hTrayMenuObject); + return hMenu; +} + +MIR_APP_DLL(HGENMENU) Menu_AddTrayMenuItem(TMO_MenuItem *pmi) +{ + HGENMENU pimi = Menu_AddItem(hTrayMenuObject, pmi, mir_strdup(pmi->pszService)); + replaceStr(pimi->UniqName, pmi->pszService); + return pimi; +} + +// called with: +// wparam - ownerdata +// lparam - lparam from winproc +static INT_PTR TrayMenuExecService(WPARAM wParam, LPARAM lParam) +{ + if (wParam != 0) + CallService((char*)wParam, 0, lParam); + + return 1; +} + +static INT_PTR FreeOwnerDataTrayMenu(WPARAM, LPARAM lParam) +{ + mir_free((char*)lParam); + return 0; +} + +void InitTrayMenus(void) +{ + CreateServiceFunction("CLISTMENUSTRAY/ExecService", TrayMenuExecService); + CreateServiceFunction("CLISTMENUSTRAY/FreeOwnerDataTrayMenu", FreeOwnerDataTrayMenu); + + hEventPreBuildTrayMenu = CreateHookableEvent(ME_CLIST_PREBUILDTRAYMENU); + + // Tray menu + hTrayMenuObject = Menu_AddObject("TrayMenu", LPGEN("Tray menu"), 0, "CLISTMENUSTRAY/ExecService"); + Menu_ConfigureObject(hTrayMenuObject, MCO_OPT_USERDEFINEDITEMS, TRUE); + Menu_ConfigureObject(hTrayMenuObject, MCO_OPT_FREE_SERVICE, "CLISTMENUSTRAY/FreeOwnerDataTrayMenu"); + Menu_ConfigureObject(hTrayMenuObject, MCO_OPT_ONADD_SERVICE, "CLISTMENUSTRAY/TrayMenuOnAddService"); +} diff --git a/src/mir_app/src/menu_utils.cpp b/src/mir_app/src/menu_utils.cpp new file mode 100644 index 0000000000..758d3c8b5e --- /dev/null +++ b/src/mir_app/src/menu_utils.cpp @@ -0,0 +1,1199 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (ñ) 2012-15 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "stdafx.h" +#include "genmenu.h" + +static bool bIsGenMenuInited; +bool bIconsDisabled; +static mir_cs csMenuHook; + +static int NextObjectId = 0x100, NextObjectMenuItemId = CLISTMENUIDMIN; + +#if defined(_DEBUG) +static void DumpMenuItem(TMO_IntMenuItem* pParent, int level = 0) +{ + char temp[ 30 ]; + memset(temp, '\t', level); + temp[ level ] = 0; + + for (TMO_IntMenuItem *pimi = pParent; pimi != NULL; pimi = pimi->next) { + Netlib_Logf(NULL, "%sMenu item %08p [%08p]: %S", temp, pimi, pimi->mi.root, pimi->mi.name.t); + + TMO_IntMenuItem *submenu = pimi->submenu.first; + if (submenu) + DumpMenuItem(submenu, level+1); + } +} + +#endif + +static int CompareMenus(const TIntMenuObject* p1, const TIntMenuObject* p2) +{ + return mir_strcmp(p1->pszName, p2->pszName); +} + +LIST g_menus(10, NumericKeySortT); + +void FreeAndNil(void **p) +{ + if (p == NULL) + return; + + if (*p != NULL) { + mir_free(*p); + *p = NULL; + } +} + +TIntMenuObject* GetMenuObjbyId(int id) +{ + switch (id) { + case MO_MAIN: id = hMainMenuObject; break; + case MO_CONTACT: id = hContactMenuObject; break; + case MO_STATUS: id = hStatusMenuObject; break; + case MO_PROTO: + if (db_get_b(NULL, "CList", "MoveProtoMenus", true)) + id = hStatusMenuObject; + else + id = hMainMenuObject; + } + + return g_menus.find((TIntMenuObject*)&id); +} + +LPTSTR GetMenuItemText(TMO_IntMenuItem *pimi) +{ + if (pimi->mi.flags & CMIF_KEEPUNTRANSLATED) + return pimi->mi.name.t; + + return TranslateTH(pimi->mi.hLangpack, pimi->mi.name.t); +} + +/////////////////////////////////////////////////////////////////////////////// + +TMO_IntMenuItem* MO_RecursiveWalkMenu(TMO_IntMenuItem *parent, pfnWalkFunc func, void* param) +{ + if (parent == NULL) + return FALSE; + + TMO_IntMenuItem *pnext; + for (TMO_IntMenuItem *pimi = parent; pimi != NULL; pimi = pnext) { + TMO_IntMenuItem *submenu = pimi->submenu.first; + pnext = pimi->next; + if (func(pimi, param)) // it can destroy the menu item + return pimi; + + if (submenu) { + TMO_IntMenuItem *res = MO_RecursiveWalkMenu(submenu, func, param); + if (res) + return res; + } + } + + return FALSE; +} + +/////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(BOOL) Menu_MeasureItem(MEASUREITEMSTRUCT *mis) +{ + if (!bIsGenMenuInited) + return FALSE; + + if (mis == NULL) + return FALSE; + + // prevent win9x from ugly menus displaying when there is no icon + mis->itemWidth = 0; + mis->itemHeight = 0; + + TMO_IntMenuItem *pimi = MO_GetIntMenuItem((HGENMENU)mis->itemData); + if (pimi == NULL) + return FALSE; + + if (pimi->iconId == -1) + return FALSE; + + mis->itemWidth = max(0, g_iIconSX - GetSystemMetrics(SM_CXMENUCHECK) + 4); + mis->itemHeight = g_iIconSY + 2; + return TRUE; +} + +/////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(BOOL) Menu_DrawItem(DRAWITEMSTRUCT *dis) +{ + if (!bIsGenMenuInited) + return FALSE; + + if (dis == NULL) + return FALSE; + + mir_cslock lck(csMenuHook); + + TMO_IntMenuItem *pimi = MO_GetIntMenuItem((HGENMENU)dis->itemData); + if (pimi == NULL || pimi->iconId == -1) + return FALSE; + + int y = (dis->rcItem.bottom - dis->rcItem.top - g_iIconSY) / 2 + 1; + if (dis->itemState & ODS_SELECTED) { + if (dis->itemState & ODS_CHECKED) { + RECT rc; + rc.left = 2; rc.right = g_iIconSX + 2; + rc.top = y; rc.bottom = rc.top + g_iIconSY + 2; + FillRect(dis->hDC, &rc, GetSysColorBrush(COLOR_HIGHLIGHT)); + ImageList_DrawEx(pimi->parent->m_hMenuIcons, pimi->iconId, dis->hDC, 2, y, 0, 0, CLR_NONE, CLR_DEFAULT, ILD_SELECTED); + } + else ImageList_DrawEx(pimi->parent->m_hMenuIcons, pimi->iconId, dis->hDC, 2, y, 0, 0, CLR_NONE, CLR_DEFAULT, ILD_FOCUS); + } + else { + if (dis->itemState & ODS_CHECKED) { + RECT rc; + rc.left = 0; rc.right = g_iIconSX + 4; + rc.top = y - 2; rc.bottom = rc.top + g_iIconSY + 4; + DrawEdge(dis->hDC, &rc, BDR_SUNKENOUTER, BF_RECT); + InflateRect(&rc, -1, -1); + COLORREF menuCol = GetSysColor(COLOR_MENU); + COLORREF hiliteCol = GetSysColor(COLOR_3DHIGHLIGHT); + HBRUSH hBrush = CreateSolidBrush(RGB((GetRValue(menuCol) + GetRValue(hiliteCol)) / 2, (GetGValue(menuCol) + GetGValue(hiliteCol)) / 2, (GetBValue(menuCol) + GetBValue(hiliteCol)) / 2)); + FillRect(dis->hDC, &rc, GetSysColorBrush(COLOR_MENU)); + DeleteObject(hBrush); + ImageList_DrawEx(pimi->parent->m_hMenuIcons, pimi->iconId, dis->hDC, 2, y, 0, 0, CLR_NONE, GetSysColor(COLOR_MENU), ILD_BLEND50); + } + else ImageList_DrawEx(pimi->parent->m_hMenuIcons, pimi->iconId, dis->hDC, 2, y, 0, 0, CLR_NONE, CLR_NONE, ILD_NORMAL); + } + return TRUE; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +int MO_RemoveAllObjects() +{ + for (int i = 0; i < g_menus.getCount(); i++) + delete g_menus[i]; + g_menus.destroy(); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +EXTERN_C MIR_APP_DLL(BOOL) Menu_ProcessHotKey(int hMenuObject, int key) +{ + if (!bIsGenMenuInited) + return -1; + + mir_cslock lck(csMenuHook); + TIntMenuObject *pmo = GetMenuObjbyId(hMenuObject); + if (pmo == NULL) + return FALSE; + + for (TMO_IntMenuItem *pimi = pmo->m_items.first; pimi != NULL; pimi = pimi->next) { + if (pimi->hotKey == 0) continue; + if (HIWORD(pimi->hotKey) != key) continue; + if (!(LOWORD(pimi->hotKey) & MOD_ALT) != !(GetKeyState(VK_MENU) & 0x8000)) continue; + if (!(LOWORD(pimi->hotKey) & MOD_CONTROL) != !(GetKeyState(VK_CONTROL) & 0x8000)) continue; + if (!(LOWORD(pimi->hotKey) & MOD_SHIFT) != !(GetKeyState(VK_SHIFT) & 0x8000)) continue; + + Menu_ProcessCommand(pimi, 0); + return TRUE; + } + + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(HGENMENU) Menu_GetProtocolRoot(PROTO_INTERFACE *pThis) +{ + if (pThis == NULL) + return 0; + + if (db_get_b(NULL, "CList", "MoveProtoMenus", TRUE)) { + if (pThis->m_hMainMenuItem != NULL) { + Menu_RemoveItem(pThis->m_hMainMenuItem); + pThis->m_hMainMenuItem = NULL; + } + return cli.pfnGetProtocolMenu(pThis->m_szModuleName); + } + + TIntMenuObject *pmo = GetMenuObjbyId(hMainMenuObject); + if (pmo == NULL) + return NULL; + + mir_cslock lck(csMenuHook); + for (TMO_IntMenuItem *p = pmo->m_items.first; p != NULL; p = p->next) + if (!mir_strcmp(p->UniqName, pThis->m_szModuleName)) + return p; + + // create protocol root in the main menu + CMenuItem mi; + mi.name.t = pThis->m_tszUserName; + mi.position = 500090000; + mi.flags = CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; + mi.hIcolibItem = pThis->m_hProtoIcon; + return pThis->m_hMainMenuItem = Menu_AddMainMenuItem(&mi); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(int) Menu_GetItemInfo(HGENMENU hMenuItem, TMO_MenuItem &pInfo) +{ + if (!bIsGenMenuInited) + return -1; + + TMO_IntMenuItem *pimi = MO_GetIntMenuItem(hMenuItem); + mir_cslock lck(csMenuHook); + if (pimi == NULL) + return -1; + + pInfo = pimi->mi; + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static int FindDefaultItem(TMO_IntMenuItem *pimi, void*) +{ + if (pimi->mi.flags & (CMIF_GRAYED | CMIF_HIDDEN)) + return FALSE; + + return (pimi->mi.flags & CMIF_DEFAULT) ? TRUE : FALSE; +} + +MIR_APP_DLL(HGENMENU) Menu_GetDefaultItem(HGENMENU hMenu) +{ + if (!bIsGenMenuInited) + return NULL; + + TMO_IntMenuItem *pimi = MO_GetIntMenuItem(hMenu); + mir_cslock lck(csMenuHook); + return (pimi) ? MO_RecursiveWalkMenu(pimi, FindDefaultItem, NULL) : NULL; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static void Menu_SetItemFlags(HGENMENU hMenuItem, bool bSet, int mask) +{ + TMO_IntMenuItem *pimi = MO_GetIntMenuItem(hMenuItem); + if (pimi == NULL) + return; + + int flags = pimi->mi.flags; + if (bSet) + flags |= mask; + else + flags &= ~mask; + + // we allow to set only first 3 bits + mir_cslock lck(csMenuHook); + pimi->mi.flags = flags | (pimi->mi.flags & 0xFFFFFFF8); +} + +MIR_APP_DLL(void) Menu_EnableItem(HGENMENU hMenuItem, bool bEnable) +{ + Menu_SetItemFlags(hMenuItem, !bEnable, CMIF_GRAYED); +} + +MIR_APP_DLL(void) Menu_ShowItem(HGENMENU hMenuItem, bool bShow) +{ + Menu_SetItemFlags(hMenuItem, !bShow, CMIF_HIDDEN); +} + +MIR_APP_DLL(void) Menu_SetChecked(HGENMENU hMenuItem, bool bSet) +{ + Menu_SetItemFlags(hMenuItem, bSet, CMIF_CHECKED); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(int) Menu_ModifyItem(HGENMENU hMenuItem, const TCHAR *ptszName, HANDLE hIcon, int iFlags) +{ + if (!bIsGenMenuInited) + return -1; + + mir_cslock lck(csMenuHook); + + TMO_IntMenuItem *pimi = MO_GetIntMenuItem(hMenuItem); + if (pimi == NULL) + return -1; + + if (ptszName != NULL) + replaceStrT(pimi->mi.name.t, ptszName); + + if (iFlags != -1) { + // we allow to set only first 3 bits + int oldflags = (pimi->mi.flags & 0xFFFFFFF8); + pimi->mi.flags = (iFlags & 0x07) | oldflags; + } + + if (hIcon != INVALID_HANDLE_VALUE && !bIconsDisabled) { + HANDLE hIcolibItem = IcoLib_IsManaged((HICON)hIcon); + if (hIcolibItem) { + HICON hIcon = IcoLib_GetIconByHandle(hIcolibItem, false); + if (hIcon != NULL) { + pimi->hIcolibItem = hIcolibItem; + pimi->iconId = ImageList_ReplaceIcon(pimi->parent->m_hMenuIcons, pimi->iconId, hIcon); + IcoLib_ReleaseIcon(hIcon); + } + else pimi->iconId = -1, pimi->hIcolibItem = NULL; + } + else { + pimi->mi.hIcolibItem = (HICON)hIcon; + if (hIcon != NULL) + pimi->iconId = ImageList_ReplaceIcon(pimi->parent->m_hMenuIcons, pimi->iconId, (HICON)hIcon); + else + pimi->iconId = -1; //fixme, should remove old icon & shuffle all iconIds + } + if (pimi->hBmp) { + DeleteObject(pimi->hBmp); + pimi->hBmp = NULL; + } + } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(void*) Menu_GetItemData(HGENMENU hMenuItem) +{ + if (!bIsGenMenuInited) + return NULL; + + mir_cslock lck(csMenuHook); + TMO_IntMenuItem *pimi = MO_GetIntMenuItem(hMenuItem); + return (pimi) ? pimi->pUserData : NULL; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +TMO_IntMenuItem *MO_GetIntMenuItem(HGENMENU wParam) +{ + TMO_IntMenuItem *result = (TMO_IntMenuItem*)wParam; + if (result == NULL) + return NULL; + + __try { + if (result->signature != MENUITEM_SIGNATURE) + result = NULL; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + result = NULL; + } + + return result; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static int FindMenuByCommand(TMO_IntMenuItem *pimi, void* pCommand) +{ + return (pimi->iCommand == (int)pCommand); +} + +int MO_ProcessCommandBySubMenuIdent(int menuID, int command, LPARAM lParam) +{ + if (!bIsGenMenuInited) + return -1; + + TMO_IntMenuItem *pimi; + { + mir_cslock lck(csMenuHook); + TIntMenuObject *pmo = GetMenuObjbyId(menuID); + if (pmo == NULL) + return -1; + + pimi = MO_RecursiveWalkMenu(pmo->m_items.first, FindMenuByCommand, (void*)command); + } + + return (pimi) ? Menu_ProcessCommand(pimi, lParam) : -1; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(BOOL) Menu_ProcessCommandById(int command, LPARAM lParam) +{ + if (!bIsGenMenuInited) + return -1; + + mir_cslock lck(csMenuHook); + for (int i = 0; i < g_menus.getCount(); i++) + if (TMO_IntMenuItem *pimi = MO_RecursiveWalkMenu(g_menus[i]->m_items.first, FindMenuByCommand, (void*)command)) + return Menu_ProcessCommand(pimi, lParam); + + return false; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(BOOL) Menu_ProcessCommand(HGENMENU hMenuItem, LPARAM lParam) +{ + if (!bIsGenMenuInited) + return false; + + TMO_IntMenuItem *pimi; + { + mir_cslock lck(csMenuHook); + if ((pimi = MO_GetIntMenuItem(hMenuItem)) == NULL) + return false; + } + + LPCSTR srvname = pimi->parent->ExecService; + CallService(srvname, (WPARAM)pimi->pUserData, lParam); + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(int) Menu_ConfigureItem(HGENMENU hItem, int iOption, INT_PTR value) +{ + if (!bIsGenMenuInited) + return -1; + + mir_cslock lck(csMenuHook); + TMO_IntMenuItem *pimi = MO_GetIntMenuItem(hItem); + if (pimi == NULL) + return -1; + + switch (iOption) { + case MCI_OPT_UNIQUENAME: + replaceStr(pimi->UniqName, (char*)value); + return 0; + + case MCI_OPT_HOTKEY: + pimi->hotKey = (DWORD)value; + return 0; + + case MCI_OPT_EXECPARAM: + pimi->execParam = value; + return 0; + } + + return 1; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(int) Menu_ConfigureObject(int hMenuObject, int setting, INT_PTR value) +{ + if (!bIsGenMenuInited) + return false; + + mir_cslock lck(csMenuHook); + TIntMenuObject *pmo = GetMenuObjbyId(hMenuObject); + if (pmo != NULL) { + switch (setting) { + case MCO_OPT_ONADD_SERVICE: + replaceStr(pmo->onAddService, (char*)value); + return true; + + case MCO_OPT_FREE_SERVICE: + replaceStr(pmo->FreeService, (char*)value); + return true; + + case MCO_OPT_CHECK_SERVICE: + replaceStr(pmo->CheckService, (char*)value); + return true; + + case MCO_OPT_USERDEFINEDITEMS: + pmo->m_bUseUserDefinedItems = (BOOL)value; + return true; + } + } + + return false; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(int) Menu_AddObject(LPCSTR szName, LPCSTR szDisplayName, LPCSTR szCheckService, LPCSTR szExecService) +{ + if (szName == NULL || szDisplayName == NULL) + return NULL; + + mir_cslock lck(csMenuHook); + + TIntMenuObject *p = new TIntMenuObject(); + p->id = NextObjectId++; + p->pszName = mir_strdup(szName); + p->ptszDisplayName = mir_a2t(szDisplayName); + p->CheckService = mir_strdup(szCheckService); + p->ExecService = mir_strdup(szExecService); + p->m_hMenuIcons = ImageList_Create(g_iIconSX, g_iIconSY, ILC_COLOR32 | ILC_MASK, 15, 100); + g_menus.insert(p); + return p->id; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(int) Menu_RemoveObject(int hMenuObject) +{ + if (!bIsGenMenuInited || hMenuObject == 0) + return -1; + + mir_cslock lck(csMenuHook); + TIntMenuObject *pmo = GetMenuObjbyId(hMenuObject); + if (pmo == NULL) + return -1; + + g_menus.remove(pmo); + delete pmo; + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// wparam = MenuItemHandle +// lparam = 0 + +static int FreeMenuItem(TMO_IntMenuItem* pimi, void*) +{ + pimi->parent->freeItem(pimi); + return FALSE; +} + +static int FindParent(TMO_IntMenuItem* pimi, void* p) +{ + return pimi->next == p; +} + +MIR_APP_DLL(int) Menu_RemoveItem(HGENMENU hMenuItem) +{ + mir_cslock lck(csMenuHook); + TMO_IntMenuItem *pimi = MO_GetIntMenuItem(hMenuItem); + if (pimi == NULL) + return -1; + + if (pimi->submenu.first) { + MO_RecursiveWalkMenu(pimi->submenu.first, FreeMenuItem, NULL); + pimi->submenu.first = NULL; + } + + TMO_IntMenuItem *prev = MO_RecursiveWalkMenu(pimi->owner->first, FindParent, pimi); + if (prev) + prev->next = pimi->next; + if (pimi->owner->first == pimi) + pimi->owner->first = pimi->next; + if (pimi->owner->last == pimi) + pimi->owner->last = prev; + + pimi->signature = 0; // invalidate all future calls to that object + pimi->parent->freeItem(pimi); + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +struct KillMenuItemsParam +{ + KillMenuItemsParam(int _hLangpack) : + hLangpack(_hLangpack), + arItems(10) + {} + + int hLangpack; + LIST arItems; +}; + +int KillMenuItems(TMO_IntMenuItem *pimi, KillMenuItemsParam* param) +{ + if (pimi->mi.hLangpack == param->hLangpack) + param->arItems.insert(pimi); + return FALSE; +} + +MIR_APP_DLL(void) KillModuleMenus(int hLangpack) +{ + if (!bIsGenMenuInited) + return; + + KillMenuItemsParam param(hLangpack); + + mir_cslock lck(csMenuHook); + for (int i = 0; i < g_menus.getCount(); i++) + MO_RecursiveWalkMenu(g_menus[i]->m_items.first, (pfnWalkFunc)KillMenuItems, ¶m); + + for (int k = 0; k < param.arItems.getCount(); k++) + Menu_RemoveItem(param.arItems[k]); +} + +/////////////////////////////////////////////////////////////////////////////// +// we presume that this function is being called inside csMenuHook only + +static int PackMenuItems(TMO_IntMenuItem *pimi, void*) +{ + pimi->iCommand = NextObjectMenuItemId++; + return FALSE; +} + +static int GetNextObjectMenuItemId() +{ + // if menu commands are exausted, pack the menu array + if (NextObjectMenuItemId >= CLISTMENUIDMAX) { + NextObjectMenuItemId = CLISTMENUIDMIN; + for (int i = 0; i < g_menus.getCount(); i++) + MO_RecursiveWalkMenu(g_menus[i]->m_items.first, PackMenuItems, NULL); + } + + return NextObjectMenuItemId++; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Adds new submenu +// Returns a handle to the newly created root item or NULL + +static int FindRoot(TMO_IntMenuItem *pimi, void *param) +{ + if (pimi->mi.name.t != NULL) + if (pimi->submenu.first && !mir_tstrcmp(pimi->mi.name.t, (TCHAR*)param)) + return TRUE; + + return FALSE; +} + +MIR_APP_DLL(HGENMENU) Menu_CreateRoot(int hMenuObject, LPCTSTR ptszName, int position, HANDLE hIcoLib, int hLang) +{ + mir_cslock lck(csMenuHook); + TIntMenuObject *pmo = GetMenuObjbyId(hMenuObject); + if (pmo == NULL) + return NULL; + + TMO_IntMenuItem *oldroot = MO_RecursiveWalkMenu(pmo->m_items.first, FindRoot, (void*)ptszName); + if (oldroot != NULL) + return oldroot; + + CMenuItem mi; + mi.flags = CMIF_TCHAR; + mi.hIcolibItem = hIcoLib; + mi.hLangpack = hLang; + mi.name.t = (TCHAR*)ptszName; + mi.position = position; + return Menu_AddItem(hMenuObject, &mi, NULL); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Adds new menu item +// Returns a handle to the newly created item or NULL + +MIR_APP_DLL(HGENMENU) Menu_AddItem(int hMenuObject, TMO_MenuItem *pmi, void *pUserData) +{ + if (!bIsGenMenuInited || pmi == NULL) + return NULL; + + mir_cslock lck(csMenuHook); + TIntMenuObject *pmo = GetMenuObjbyId(hMenuObject); + if (pmo == NULL) + return NULL; + + TMO_IntMenuItem* p = (TMO_IntMenuItem*)mir_calloc(sizeof(TMO_IntMenuItem)); + p->parent = pmo; + p->signature = MENUITEM_SIGNATURE; + p->iCommand = GetNextObjectMenuItemId(); + p->mi = *pmi; + p->iconId = -1; + p->OverrideShow = TRUE; + p->originalPosition = pmi->position; + p->pUserData = pUserData; + + if (pmi->flags & CMIF_UNICODE) + p->mi.name.t = mir_tstrdup(pmi->name.t); + else + p->mi.name.t = mir_a2u(pmi->name.a); + + if (pmi->hIcon != NULL && !bIconsDisabled) { + HANDLE hIcolibItem = IcoLib_IsManaged(pmi->hIcon); + if (hIcolibItem != NULL) { + HICON hIcon = IcoLib_GetIconByHandle(hIcolibItem, false); + p->iconId = ImageList_AddIcon(pmo->m_hMenuIcons, hIcon); + p->hIcolibItem = hIcolibItem; + IcoLib_ReleaseIcon(hIcon); + } + else p->iconId = ImageList_AddIcon(pmo->m_hMenuIcons, pmi->hIcon); + } + + TMO_IntMenuItem *pRoot = (p->mi.root != NULL) ? MO_GetIntMenuItem(p->mi.root) : NULL; + if (pRoot) { + p->owner = &pRoot->submenu; + + if (pRoot->iconId == -1) + pRoot->iconId = p->iconId; + } + else p->owner = &pmo->m_items; + + if (!p->owner->first) + p->owner->first = p; + if (p->owner->last) + p->owner->last->next = p; + p->owner->last = p; + return p; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// wparam = MenuObjectHandle +// lparam = PMO_MenuItem + +static int WhereToPlace(HMENU hMenu, TMO_MenuItem *mi) +{ + MENUITEMINFO mii = { 0 }; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_SUBMENU | MIIM_DATA; + for (int i = GetMenuItemCount(hMenu) - 1; i >= 0; i--) { + GetMenuItemInfo(hMenu, i, TRUE, &mii); + if (mii.fType != MFT_SEPARATOR) { + TMO_IntMenuItem *pimi = MO_GetIntMenuItem((HGENMENU)mii.dwItemData); + if (pimi != NULL) + if (pimi->mi.position <= mi->position) + return i + 1; + } + } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static DWORD GetMenuItemType(HMENU hMenu, int uItem) +{ + MENUITEMINFO mii = { 0 }; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_TYPE; + GetMenuItemInfo(hMenu, uItem, TRUE, &mii); + return mii.fType; +} + +static UINT GetMenuItemTypeData(HMENU hMenu, int uItem, TMO_IntMenuItem* &p) +{ + MENUITEMINFO mii = { 0 }; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_DATA | MIIM_TYPE; + GetMenuItemInfo(hMenu, uItem, TRUE, &mii); + p = MO_GetIntMenuItem((HGENMENU)mii.dwItemData); + return mii.fType; +} + +static void InsertSeparator(HMENU hMenu, int uItem) +{ + MENUITEMINFO mii = { 0 }; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_TYPE; + mii.fType = MFT_SEPARATOR; + InsertMenuItem(hMenu, uItem, TRUE, &mii); +} + +static void InsertMenuItemWithSeparators(HMENU hMenu, int uItem, MENUITEMINFO *lpmii) +{ + TMO_IntMenuItem *pimi = MO_GetIntMenuItem((HGENMENU)lpmii->dwItemData), *p; + if (pimi == NULL) + return; + + // check for separator before + if (uItem) { + UINT fType = GetMenuItemTypeData(hMenu, uItem - 1, p); + if (p != NULL && fType != MFT_SEPARATOR) { + if ((p->mi.position / SEPARATORPOSITIONINTERVAL) != (pimi->mi.position / SEPARATORPOSITIONINTERVAL)) { + // but might be supposed to be after the next one instead + if (!(uItem < GetMenuItemCount(hMenu) && GetMenuItemType(hMenu, uItem) == MFT_SEPARATOR)) + InsertSeparator(hMenu, uItem); + uItem++; + } + } + } + + // check for separator after + if (uItem < GetMenuItemCount(hMenu)) { + UINT fType = GetMenuItemTypeData(hMenu, uItem, p); + if (p != NULL && fType != MFT_SEPARATOR) + if ((p->mi.position / SEPARATORPOSITIONINTERVAL) != (pimi->mi.position / SEPARATORPOSITIONINTERVAL)) + InsertSeparator(hMenu, uItem); + } + + // create local copy *lpmii so we can change some flags + MENUITEMINFO mii = *lpmii; + + int count = GetMenuItemCount(hMenu); + if (count != 0 && (count % 33) == 0 && pimi->mi.root != NULL) { + if (!(mii.fMask & MIIM_FTYPE)) + mii.fType = 0; + mii.fMask |= MIIM_FTYPE; + mii.fType |= MFT_MENUBARBREAK; + } + + if (!pimi->CustomName) + mii.dwTypeData = GetMenuItemText(pimi); + + InsertMenuItem(hMenu, uItem, TRUE, &mii); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +#ifdef _DEBUG +#define PUTPOSITIONSONMENU +#endif + +void GetMenuItemName(TMO_IntMenuItem *pMenuItem, char* pszDest, size_t cbDestSize) +{ + if (pMenuItem->UniqName) + mir_snprintf(pszDest, cbDestSize, "{%s}", pMenuItem->UniqName); + else if (pMenuItem->mi.flags & CMIF_UNICODE) + mir_snprintf(pszDest, cbDestSize, "{%s}", (char*)_T2A(pMenuItem->mi.name.t)); + else + mir_snprintf(pszDest, cbDestSize, "{%s}", pMenuItem->mi.name.t); +} + +static HMENU BuildRecursiveMenu(HMENU hMenu, TMO_IntMenuItem *pRootMenu, INT_PTR iRootLevel, WPARAM wParam, LPARAM lParam) +{ + if (pRootMenu == NULL) + return NULL; + + TIntMenuObject *pmo = pRootMenu->parent; + + if (iRootLevel == 0) + while (GetMenuItemCount(hMenu) > 0) + DeleteMenu(hMenu, 0, MF_BYPOSITION); + + for (TMO_IntMenuItem *pmi = pRootMenu; pmi != NULL; pmi = pmi->next) { + TMO_MenuItem *mi = &pmi->mi; + if (mi->flags & CMIF_HIDDEN) + continue; + + if (pmo->CheckService != NULL) { + TCheckProcParam CheckParam; + CheckParam.wParam = wParam; + CheckParam.lParam = lParam; + CheckParam.MenuItemOwnerData = pmi->pUserData; + CheckParam.MenuItemHandle = pmi; + if (CallService(pmo->CheckService, (WPARAM)&CheckParam, 0) == FALSE) + continue; + } + + /**************************************/ + if (iRootLevel == 0 && mi->root == NULL && pmo->m_bUseUserDefinedItems) { + char DBString[256]; + DBVARIANT dbv = { 0 }; + int pos; + char MenuNameItems[256]; + mir_snprintf(MenuNameItems, _countof(MenuNameItems), "%s_Items", pmo->pszName); + + char menuItemName[256]; + GetMenuItemName(pmi, menuItemName, sizeof(menuItemName)); + + // check if it visible + mir_snprintf(DBString, _countof(DBString), "%s_visible", menuItemName); + if (db_get_b(NULL, MenuNameItems, DBString, -1) == -1) + db_set_b(NULL, MenuNameItems, DBString, 1); + + pmi->OverrideShow = TRUE; + if (!db_get_b(NULL, MenuNameItems, DBString, 1)) { + pmi->OverrideShow = FALSE; + continue; // find out what value to return if not getting added + } + + // mi.name.t + mir_snprintf(DBString, _countof(DBString), "%s_name", menuItemName); + if (!db_get_ts(NULL, MenuNameItems, DBString, &dbv)) { + if (mir_tstrlen(dbv.ptszVal) > 0) + replaceStrT(pmi->CustomName, dbv.ptszVal); + db_free(&dbv); + } + + mir_snprintf(DBString, _countof(DBString), "%s_pos", menuItemName); + if ((pos = db_get_dw(NULL, MenuNameItems, DBString, -1)) == -1) { + db_set_dw(NULL, MenuNameItems, DBString, mi->position); + if (pmi->submenu.first) + mi->position = 0; + } + else mi->position = pos; + } + + /**************************************/ + + if (iRootLevel != (INT_PTR)pmi->mi.root) + continue; + + int i = WhereToPlace(hMenu, mi); + + MENUITEMINFO mii = { 0 }; + mii.cbSize = sizeof(mii); + mii.dwItemData = (LPARAM)pmi; + mii.fMask = MIIM_DATA | MIIM_ID | MIIM_STRING; + if (pmi->iconId != -1) { + mii.fMask |= MIIM_BITMAP; + if (IsWinVerVistaPlus() && IsThemeActive()) { + if (pmi->hBmp == NULL) + pmi->hBmp = ConvertIconToBitmap(NULL, pmi->parent->m_hMenuIcons, pmi->iconId); + mii.hbmpItem = pmi->hBmp; + } + else mii.hbmpItem = HBMMENU_CALLBACK; + } + + mii.fMask |= MIIM_STATE; + mii.fState = ((pmi->mi.flags & CMIF_GRAYED) ? MFS_GRAYED : MFS_ENABLED); + mii.fState |= ((pmi->mi.flags & CMIF_CHECKED) ? MFS_CHECKED : MFS_UNCHECKED); + if (pmi->mi.flags & CMIF_DEFAULT) + mii.fState |= MFS_DEFAULT; + + mii.dwTypeData = (pmi->CustomName) ? pmi->CustomName : mi->name.t; + + // it's a submenu + if (pmi->submenu.first) { + mii.fMask |= MIIM_SUBMENU; + mii.hSubMenu = CreatePopupMenu(); + +#ifdef PUTPOSITIONSONMENU + if (GetKeyState(VK_CONTROL) & 0x8000) { + TCHAR str[256]; + mir_sntprintf(str, _countof(str), _T("%s (%d, id %x)"), mi->name.a, mi->position, mii.dwItemData); + mii.dwTypeData = str; + } +#endif + + InsertMenuItemWithSeparators(hMenu, i, &mii); + BuildRecursiveMenu(mii.hSubMenu, pmi->submenu.first, LPARAM(pmi), wParam, lParam); + } + else { + mii.wID = pmi->iCommand; + +#ifdef PUTPOSITIONSONMENU + if (GetKeyState(VK_CONTROL) & 0x8000) { + TCHAR str[256]; + mir_sntprintf(str, _countof(str), _T("%s (%d, id %x)"), mi->name.a, mi->position, mii.dwItemData); + mii.dwTypeData = str; + } +#endif + + if (pmo->onAddService != NULL) + if (CallService(pmo->onAddService, (WPARAM)&mii, (LPARAM)pmi) == FALSE) + continue; + + InsertMenuItemWithSeparators(hMenu, i, &mii); + } + } + + return hMenu; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// wparam started hMenu +// lparam ListParam* +// result hMenu + +EXTERN_C MIR_APP_DLL(HMENU) Menu_Build(HMENU parent, int hMenuObject, WPARAM wParam, LPARAM lParam) +{ + if (!bIsGenMenuInited) + return NULL; + + mir_cslock lck(csMenuHook); + + TIntMenuObject *pmo = GetMenuObjbyId(hMenuObject); + if (pmo == NULL) + return NULL; + + #if defined(_DEBUG) + // DumpMenuItem(pmo->m_items.first); + #endif + + return BuildRecursiveMenu(parent, pmo->m_items.first, 0, wParam, lParam); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// iconlib in menu + +static int MO_ReloadIcon(TMO_IntMenuItem *pmi, void*) +{ + if (pmi->hIcolibItem) { + HICON newIcon = IcoLib_GetIconByHandle(pmi->hIcolibItem, false); + if (newIcon) + ImageList_ReplaceIcon(pmi->parent->m_hMenuIcons, pmi->iconId, newIcon); + + IcoLib_ReleaseIcon(newIcon); + } + + return FALSE; +} + +int OnIconLibChanges(WPARAM, LPARAM) +{ + { + mir_cslock lck(csMenuHook); + for (int mo = 0; mo < g_menus.getCount(); mo++) + if (hStatusMenuObject != g_menus[mo]->id) //skip status menu + MO_RecursiveWalkMenu(g_menus[mo]->m_items.first, MO_ReloadIcon, 0); + } + + cli.pfnReloadProtoMenus(); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static int MO_RegisterIcon(TMO_IntMenuItem *pmi, void*) +{ + TCHAR *uname = (pmi->UniqName) ? mir_a2t(pmi->UniqName) : mir_tstrdup(pmi->CustomName), + *descr = GetMenuItemText(pmi); + + if (!uname && !descr) + return FALSE; + + if (!pmi->hIcolibItem) { + HICON hIcon = ImageList_GetIcon(pmi->parent->m_hMenuIcons, pmi->iconId, 0); + + TCHAR sectionName[256]; + mir_sntprintf(sectionName, _countof(sectionName), LPGENT("Menu icons") _T("/%s"), TranslateTS(pmi->parent->ptszDisplayName)); + + char iconame[256]; + mir_snprintf(iconame, _countof(iconame), "genmenu_%s_%s", pmi->parent->pszName, uname && *uname ? uname : descr); + + // remove '&' + if (descr) { + descr = NEWTSTR_ALLOCA(descr); + + for (TCHAR *p = descr; *p; p++) { + if ((p = _tcschr(p, '&')) == NULL) + break; + + memmove(p, p + 1, sizeof(TCHAR)*(mir_tstrlen(p + 1) + 1)); + if (*p == '\0') + p++; + } + } + + SKINICONDESC sid = { 0 }; + sid.flags = SIDF_TCHAR; + sid.section.t = sectionName; + sid.pszName = iconame; + sid.description.t = descr; + sid.hDefaultIcon = hIcon; + pmi->hIcolibItem = IcoLib_AddIcon(&sid, 0); + + Safe_DestroyIcon(hIcon); + if (hIcon = IcoLib_GetIcon(iconame)) { + ImageList_ReplaceIcon(pmi->parent->m_hMenuIcons, pmi->iconId, hIcon); + IcoLib_ReleaseIcon(hIcon); + } + } + + mir_free(uname); + return FALSE; +} + +int RegisterAllIconsInIconLib() +{ + // register all icons + for (int mo = 0; mo < g_menus.getCount(); mo++) { + if (hStatusMenuObject == g_menus[mo]->id) //skip status menu + continue; + + MO_RecursiveWalkMenu(g_menus[mo]->m_items.first, MO_RegisterIcon, 0); + } + + return 0; +} + +int TryProcessDoubleClick(MCONTACT hContact) +{ + TIntMenuObject *pmo = GetMenuObjbyId(hContactMenuObject); + if (pmo != NULL) { + NotifyEventHooks(hPreBuildContactMenuEvent, hContact, 0); + + TMO_IntMenuItem *pimi = Menu_GetDefaultItem(pmo->m_items.first); + if (pimi != NULL) { + Menu_ProcessCommand(pimi, hContact); + return 0; + } + } + + return 1; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Static services + +int posttimerid; + +static VOID CALLBACK PostRegisterIcons(HWND, UINT, UINT_PTR, DWORD) +{ + KillTimer(0, posttimerid); + RegisterAllIconsInIconLib(); +} + +static int OnModulesLoaded(WPARAM, LPARAM) +{ + posttimerid = SetTimer(NULL, 0, 5, (TIMERPROC)PostRegisterIcons); + HookEvent(ME_SKIN2_ICONSCHANGED, OnIconLibChanges); + return 0; +} + +int InitGenMenu() +{ + bIconsDisabled = db_get_b(NULL, "CList", "DisableMenuIcons", 0) != 0; + bIsGenMenuInited = true; + + HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded); + HookEvent(ME_OPT_INITIALISE, GenMenuOptInit); + return 0; +} + +int UnitGenMenu() +{ + if (bIsGenMenuInited) { + mir_cslock lck(csMenuHook); + MO_RemoveAllObjects(); + bIsGenMenuInited = false; + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +TIntMenuObject::TIntMenuObject() +{ +} + +TIntMenuObject::~TIntMenuObject() +{ + MO_RecursiveWalkMenu(m_items.first, FreeMenuItem, NULL); + + FreeAndNil((void**)&FreeService); + FreeAndNil((void**)&onAddService); + FreeAndNil((void**)&CheckService); + FreeAndNil((void**)&ExecService); + FreeAndNil((void**)&ptszDisplayName); + FreeAndNil((void**)&pszName); + + ImageList_Destroy(m_hMenuIcons); +} + +void TIntMenuObject::freeItem(TMO_IntMenuItem *p) +{ + if (FreeService) + CallService(FreeService, (WPARAM)p, (LPARAM)p->pUserData); + + p->signature = 0; + FreeAndNil((void**)&p->mi.name.t); + FreeAndNil((void**)&p->UniqName); + FreeAndNil((void**)&p->CustomName); + if (p->hBmp) DeleteObject(p->hBmp); + mir_free(p); +} diff --git a/src/mir_app/src/mir_app.def b/src/mir_app/src/mir_app.def index 584a79020a..3fbf3bff93 100644 --- a/src/mir_app/src/mir_app.def +++ b/src/mir_app/src/mir_app.def @@ -233,3 +233,5 @@ Menu_BuildSubGroupMenu @230 Menu_AddGroupMenuItem @231 Menu_AddSubGroupMenuItem @232 Menu_BuildGroupMenu @233 +Menu_AddTrayMenuItem @234 +Menu_BuildTrayMenu @235 diff --git a/src/mir_app/src/mir_app64.def b/src/mir_app/src/mir_app64.def index 52c1014550..9f72915c5f 100644 --- a/src/mir_app/src/mir_app64.def +++ b/src/mir_app/src/mir_app64.def @@ -233,3 +233,5 @@ Menu_BuildSubGroupMenu @230 Menu_AddGroupMenuItem @231 Menu_AddSubGroupMenuItem @232 Menu_BuildGroupMenu @233 +Menu_AddTrayMenuItem @234 +Menu_BuildTrayMenu @235 -- cgit v1.2.3