/* Miranda NG: the free IM client for Microsoft* Windows* Copyright (C) 2012-13 Miranda NG 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 "..\..\core\commonheaders.h" struct StatusIconChild : public MZeroedObject { ~StatusIconChild() { mir_free(szTooltip); } HANDLE hContact; HICON hIcon, hIconDisabled; int flags; char *szTooltip; }; struct StatusIconMain : public MZeroedObject { StatusIconMain() : arChildren(3, HandleKeySortT) {} ~StatusIconMain() { mir_free(sid.szModule); mir_free(sid.szTooltip); } StatusIconData sid; OBJLIST arChildren; }; static int CompareIcons(const StatusIconMain *p1, const StatusIconMain *p2) { int res = strcmp(p1->sid.szModule, p2->sid.szModule); if (res) return res; return p1->sid.dwId - p2->sid.dwId; } static OBJLIST arIcons(3, CompareIcons); static HANDLE hHookIconsChanged; INT_PTR ModifyStatusIcon(WPARAM wParam, LPARAM lParam) { StatusIconData *sid = (StatusIconData *)lParam; if (sid == NULL || sid->cbSize != sizeof(StatusIconData)) return 1; StatusIconMain *p = arIcons.find((StatusIconMain*)sid); if (p == NULL) return 1; HANDLE hContact = (HANDLE)wParam; if (hContact == NULL) { memcpy(&p->sid, sid, sizeof(p->sid)); replaceStr(p->sid.szModule, sid->szModule); replaceStr(p->sid.szTooltip, sid->szTooltip); NotifyEventHooks(hHookIconsChanged, NULL, (LPARAM)p); return 0; } StatusIconChild *pc = p->arChildren.find((StatusIconChild*)&hContact); if (pc == NULL) { pc = new StatusIconChild(); pc->hContact = hContact; p->arChildren.insert(pc); } pc->flags = sid->flags; pc->hIcon = sid->hIcon; pc->hIconDisabled = sid->hIconDisabled; replaceStr(pc->szTooltip, sid->szTooltip); NotifyEventHooks(hHookIconsChanged, wParam, (LPARAM)p); return 0; } static INT_PTR AddStatusIcon(WPARAM wParam, LPARAM lParam) { StatusIconData *sid = (StatusIconData *)lParam; if (sid == NULL || sid->cbSize != sizeof(StatusIconData)) return 1; StatusIconMain *p = arIcons.find((StatusIconMain*)sid); if (p != NULL) return ModifyStatusIcon(0, lParam); p = new StatusIconMain; memcpy(&p->sid, sid, sizeof(p->sid)); p->sid.szModule = mir_strdup(sid->szModule); p->sid.szTooltip = mir_strdup(sid->szTooltip); arIcons.insert(p); NotifyEventHooks(hHookIconsChanged, NULL, (LPARAM)p); return 0; } static INT_PTR RemoveStatusIcon(WPARAM wParam, LPARAM lParam) { StatusIconData *sid = (StatusIconData *)lParam; if (sid == NULL || sid->cbSize != sizeof(StatusIconData)) return 1; StatusIconMain *p = arIcons.find((StatusIconMain*)sid); if (p == NULL) return 1; arIcons.remove(p); return 0; } static INT_PTR GetNthIcon(WPARAM wParam, LPARAM lParam) { static StatusIconData res; for (int i=arIcons.getCount()-1, nVis = 0; i >= 0; i--) { StatusIconMain &p = arIcons[i]; StatusIconChild *pc = p.arChildren.find((StatusIconChild*)&wParam); if (pc) { if (pc->flags & MBF_HIDDEN) continue; } else if (p.sid.flags & MBF_HIDDEN) continue; if (nVis == (int)lParam) { memcpy(&res, &p, sizeof(res)); if (pc) { res.hIcon = pc->hIcon; res.hIconDisabled = pc->hIconDisabled; res.flags = pc->flags; res.szTooltip = pc->szTooltip; } return (INT_PTR)&res; } nVis++; } return 0; } ///////////////////////////////////////////////////////////////////////////////////////// static int OnWindowEvent(WPARAM, LPARAM lParam) { MessageWindowEventData *evt = (MessageWindowEventData*)lParam; if (evt->uType == MSG_WINDOW_EVT_CLOSE) { for (int i=0; i < arIcons.getCount(); i++) { StatusIconMain &p = arIcons[i]; p.arChildren.remove((StatusIconChild*)&evt->hContact); } } return 0; } static int OnModulesLoaded(WPARAM, LPARAM) { HookEvent(ME_MSG_WINDOWEVENT, OnWindowEvent); return 0; } int LoadSrmmModule() { CreateServiceFunction(MS_MSG_ADDICON, AddStatusIcon); CreateServiceFunction(MS_MSG_REMOVEICON, RemoveStatusIcon); CreateServiceFunction(MS_MSG_MODIFYICON, ModifyStatusIcon); CreateServiceFunction(MS_MSG_GETNTHICON, GetNthIcon); HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded); hHookIconsChanged = CreateHookableEvent(ME_MSG_ICONSCHANGED); return 0; } void UnloadSrmmModule() { arIcons.destroy(); NotifyEventHooks(hHookIconsChanged, NULL, NULL); DestroyHookableEvent(hHookIconsChanged); }