From 48540940b6c28bb4378abfeb500ec45a625b37b6 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Tue, 15 May 2012 10:38:20 +0000 Subject: initial commit git-svn-id: http://svn.miranda-ng.org/main/trunk@2 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/tabsrmm/src/trayicon.cpp | 374 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 374 insertions(+) create mode 100644 plugins/tabsrmm/src/trayicon.cpp (limited to 'plugins/tabsrmm/src/trayicon.cpp') diff --git a/plugins/tabsrmm/src/trayicon.cpp b/plugins/tabsrmm/src/trayicon.cpp new file mode 100644 index 0000000000..28de552468 --- /dev/null +++ b/plugins/tabsrmm/src/trayicon.cpp @@ -0,0 +1,374 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda IM: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 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. + * + * part of tabSRMM messaging plugin for Miranda. + * + * This code is based on and still contains large parts of the the + * original chat module for Miranda IM, written and copyrighted + * by Joergen Persson in 2005. + * + * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: trayicon.cpp 13447 2011-03-14 19:55:07Z george.hazan $ + * + * The code that creates and animates the tray icon. + * + */ + +#include "commonheaders.h" +#pragma hdrstop +//#include "m_toptoolbar.h" + +static BOOL isAnimThreadRunning = TRUE; +static HANDLE hTrayAnimThread = 0; +static HICON hIconTrayCurrent = 0; +HANDLE g_hEvent = 0; + +static TCHAR g_eventName[100]; + +static unsigned __stdcall TrayAnimThread(LPVOID vParam) +{ + int iAnimMode = (PluginConfig.m_AnimTrayIcons[0] && PluginConfig.m_AnimTrayIcons[1] && PluginConfig.m_AnimTrayIcons[2] && + PluginConfig.m_AnimTrayIcons[3]); + DWORD dwElapsed = 0, dwAnimStep = 0; + HICON hIconDefault = iAnimMode ? PluginConfig.m_AnimTrayIcons[0] : PluginConfig.g_iconContainer; + DWORD idleTimer = 0; + HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, g_eventName); + + do { + if (isAnimThreadRunning && PluginConfig.m_UnreadInTray == 0) { + if (hIconTrayCurrent != hIconDefault) + FlashTrayIcon(hIconDefault); // restore default icon + PluginConfig.m_TrayFlashState = 0; + + dwElapsed = 0; + dwAnimStep = 0; + WaitForSingleObject(hEvent, 30000); + ResetEvent(hEvent); + idleTimer += 2000; + } + if (!isAnimThreadRunning) { + if (hIconTrayCurrent != hIconDefault) + FlashTrayIcon(hIconDefault); // restore default icon + PluginConfig.m_TrayFlashState = 0; + break; + } + if (PluginConfig.m_UnreadInTray) { + if (iAnimMode) { + dwAnimStep++; + if (dwAnimStep > 3) + dwAnimStep = 0; + FlashTrayIcon(PluginConfig.m_AnimTrayIcons[dwAnimStep]); // restore default icon + } + else { // simple flashing + dwElapsed += 200; + if (dwElapsed >= 600) { + PluginConfig.m_TrayFlashState = !PluginConfig.m_TrayFlashState; + dwElapsed = 0; + FlashTrayIcon(PluginConfig.m_TrayFlashState ? 0 : hIconDefault); // restore default icon + } + } + Sleep(200); + idleTimer += 200; + } + if (idleTimer >= 2000) { + idleTimer = 0; + } + } + while (isAnimThreadRunning); + CloseHandle(hEvent); + return 0; +} + +void TSAPI CreateTrayMenus(int mode) +{ + if (mode) { + mir_sntprintf(g_eventName, 100, _T("tsr_evt_%d"), GetCurrentThreadId()); + g_hEvent = CreateEvent(NULL, FALSE, FALSE, g_eventName); + isAnimThreadRunning = TRUE; + hTrayAnimThread = (HANDLE)mir_forkthreadex(TrayAnimThread, NULL, 16000, NULL); + + PluginConfig.g_hMenuTrayUnread = CreatePopupMenu(); + PluginConfig.g_hMenuFavorites = CreatePopupMenu(); + PluginConfig.g_hMenuRecent = CreatePopupMenu(); + PluginConfig.g_hMenuTrayContext = GetSubMenu(PluginConfig.g_hMenuContext, 6); + ModifyMenu(PluginConfig.g_hMenuTrayContext, 0, MF_BYPOSITION | MF_POPUP, + (UINT_PTR)PluginConfig.g_hMenuFavorites, CTranslator::get(CTranslator::GEN_FAVORITES)); + ModifyMenu(PluginConfig.g_hMenuTrayContext, 2, MF_BYPOSITION | MF_POPUP, + (UINT_PTR)PluginConfig.g_hMenuRecent, CTranslator::get(CTranslator::GEN_RECENT_SESSIONS)); + LoadFavoritesAndRecent(); + } + else { + isAnimThreadRunning = FALSE; + SetEvent(g_hEvent); + WaitForSingleObject(hTrayAnimThread, 5000); + CloseHandle(hTrayAnimThread); + CloseHandle(g_hEvent); + g_hEvent = 0; + hTrayAnimThread = 0; + if (PluginConfig.g_hMenuTrayUnread != 0) { + DestroyMenu(PluginConfig.g_hMenuTrayUnread); + PluginConfig.g_hMenuTrayUnread = 0; + } + if (PluginConfig.g_hMenuFavorites != 0) { + DestroyMenu(PluginConfig.g_hMenuFavorites); + PluginConfig.g_hMenuFavorites = 0; + } + if (PluginConfig.g_hMenuRecent != 0) { + DestroyMenu(PluginConfig.g_hMenuRecent); + PluginConfig.g_hMenuRecent = 0; + } + } +} +/* + * create a system tray icon, create all necessary submenus + */ + +void TSAPI CreateSystrayIcon(int create) +{ + NOTIFYICONDATA nim; + + nim.cbSize = sizeof(nim); + nim.hWnd = PluginConfig.g_hwndHotkeyHandler; + nim.uID = 100; + nim.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; + nim.hIcon = PluginConfig.g_iconContainer; + nim.uCallbackMessage = DM_TRAYICONNOTIFY; + mir_sntprintf(nim.szTip, 64, _T("%s"), _T("tabSRMM")); + if (create && !nen_options.bTrayExist) { + Shell_NotifyIcon(NIM_ADD, &nim); + nen_options.bTrayExist = TRUE; + hIconTrayCurrent = 0; + SetEvent(g_hEvent); + } + else if (create == FALSE && nen_options.bTrayExist) { + Shell_NotifyIcon(NIM_DELETE, &nim); + nen_options.bTrayExist = FALSE; + } +} + +static BOOL CALLBACK FindTrayWnd(HWND hwnd, LPARAM lParam) +{ + TCHAR szClassName[256]; + GetClassName(hwnd, szClassName, 255); + + if (_tcscmp(szClassName, _T("TrayNotifyWnd")) == 0) { + RECT *pRect = (RECT *) lParam; + GetWindowRect(hwnd, pRect); + return TRUE; + } + if (_tcscmp(szClassName, _T("TrayClockWClass")) == 0) { + RECT *pRect = (RECT *) lParam; + RECT rectClock; + GetWindowRect(hwnd, &rectClock); + if (rectClock.bottom < pRect->bottom - 5) // 10 = random fudge factor. + pRect->top = rectClock.bottom; + else + pRect->right = rectClock.left; + return FALSE; + } + return TRUE; +} + +static void GetTrayWindowRect(LPRECT lprect) +{ + HWND hShellTrayWnd = FindWindow(_T("Shell_TrayWnd"), NULL); + if (hShellTrayWnd) { + GetWindowRect(hShellTrayWnd, lprect); + EnumChildWindows(hShellTrayWnd, FindTrayWnd, (LPARAM)lprect); + return; + } +} + +/* + * flash the tray icon + * mode = 0 - continue to flash + * mode = 1 - restore the original icon + */ + +void TSAPI FlashTrayIcon(HICON hIcon) +{ + NOTIFYICONDATA nim; + + hIconTrayCurrent = hIcon; + + if (nen_options.bTraySupport) { + nim.cbSize = sizeof(nim); + nim.hWnd = PluginConfig.g_hwndHotkeyHandler; + nim.uID = 100; + nim.uFlags = NIF_ICON; + nim.hIcon = hIcon; + Shell_NotifyIcon(NIM_MODIFY, &nim); + } +} + +/* + * add a contact to recent or favorites menu + * mode = 1, add + * mode = 0, only modify it.. + * hMenu specifies the menu handle (the menus are identical...) + * cares about updating the menu entry. It sets the hIcon (proto status icon) in + * dwItemData of the the menu entry, so that the WM_DRAWITEM handler can retrieve it + * w/o costly service calls. + * + * Also, the function does housekeeping on the Recent Sessions menu to enforce the + * maximum number of allowed entries (20 at the moment). The oldest (topmost) entry + * is deleted, if necessary. + */ + +void TSAPI AddContactToFavorites(HANDLE hContact, const TCHAR *szNickname, const char *szProto, TCHAR *szStatus, WORD wStatus, HICON hIcon, BOOL mode, HMENU hMenu) +{ + MENUITEMINFO mii = {0}; + TCHAR szMenuEntry[80]; + TCHAR szFinalNick[100]; + + if (szNickname == NULL) { + mir_sntprintf(szFinalNick, safe_sizeof(szFinalNick), _T("%s"), (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR)); + } + else { + _tcsncpy(szFinalNick, szNickname, 100); + szFinalNick[99] = 0; + } + + if (szProto == NULL) + szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (szProto) { + if (wStatus == 0) + wStatus = DBGetContactSettingWord((HANDLE)hContact, szProto, "Status", ID_STATUS_OFFLINE); + if (szStatus == NULL) + szStatus = (TCHAR *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, wStatus, GSMDF_TCHAR); + } + else + return; + + if (hIcon == 0) + hIcon = LoadSkinnedProtoIcon(szProto, wStatus); + + PROTOACCOUNT *acc = (PROTOACCOUNT *)CallService(MS_PROTO_GETACCOUNT, (WPARAM)0, (LPARAM)szProto); + + if(acc && acc->tszAccountName) { + mii.cbSize = sizeof(mii); + mir_sntprintf(szMenuEntry, safe_sizeof(szMenuEntry), _T("%s: %s (%s)"), acc->tszAccountName, szFinalNick, szStatus); + if (mode) { + if (hMenu == PluginConfig.g_hMenuRecent) { + if (CheckMenuItem(hMenu, (UINT_PTR)hContact, MF_BYCOMMAND | MF_UNCHECKED) == 0) { + DeleteMenu(hMenu, (UINT_PTR)hContact, MF_BYCOMMAND); + goto addnew; // move to the end of the menu... + } + if (GetMenuItemCount(PluginConfig.g_hMenuRecent) > nen_options.wMaxRecent) { // throw out oldest entry in the recent menu... + UINT uid = GetMenuItemID(hMenu, 0); + if (uid) { + DeleteMenu(hMenu, (UINT_PTR)0, MF_BYPOSITION); + M->WriteDword((HANDLE)uid, SRMSGMOD_T, "isRecent", 0); + } + } + addnew: + M->WriteDword(hContact, SRMSGMOD_T, "isRecent", time(NULL)); + AppendMenu(hMenu, MF_BYCOMMAND, (UINT_PTR)hContact, szMenuEntry); + } + else if (hMenu == PluginConfig.g_hMenuFavorites) { // insert the item sorted... + MENUITEMINFO mii2 = {0}; + TCHAR szBuffer[142]; + int i, c = GetMenuItemCount(PluginConfig.g_hMenuFavorites); + mii2.fMask = MIIM_STRING; + mii2.cbSize = sizeof(mii2); + if (c == 0) + InsertMenu(PluginConfig.g_hMenuFavorites, 0, MF_BYPOSITION, (UINT_PTR)hContact, szMenuEntry); + else { + for (i = 0; i <= c; i++) { + mii2.cch = 0; + mii2.dwTypeData = NULL; + GetMenuItemInfo(PluginConfig.g_hMenuFavorites, i, TRUE, &mii2); + mii2.cch++; + mii2.dwTypeData = szBuffer; + GetMenuItemInfo(PluginConfig.g_hMenuFavorites, i, TRUE, &mii2); + if (_tcsncmp((TCHAR *)mii2.dwTypeData, szMenuEntry, 140) > 0 || i == c) { + InsertMenu(PluginConfig.g_hMenuFavorites, i, MF_BYPOSITION, (UINT_PTR)hContact, szMenuEntry); + break; + } + } + } + } + } + mii.fMask = MIIM_BITMAP | MIIM_DATA; + if (!mode) { + mii.fMask |= MIIM_STRING; + mii.dwTypeData = (LPTSTR)szMenuEntry; + mii.cch = lstrlen(szMenuEntry) + 1; + } + mii.hbmpItem = HBMMENU_CALLBACK; + mii.dwItemData = (ULONG_PTR)hIcon; + SetMenuItemInfo(hMenu, (UINT)hContact, FALSE, &mii); + } +} + +/* + * called by CreateSysTrayIcon(), usually on startup or when you activate tray support + * at runtime. + * scans the contact db for favorites or recent session entries and builds the menus. + */ + +typedef struct _recentEntry { + DWORD dwTimestamp; + HANDLE hContact; +} RCENTRY; + +void TSAPI LoadFavoritesAndRecent() +{ + RCENTRY *recentEntries, rceTemp; + DWORD dwRecent; + int iIndex = 0, i, j; + HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + recentEntries = new RCENTRY[nen_options.wMaxRecent + 1]; + if (recentEntries != NULL) { + while (hContact != 0) { + if (M->GetByte(hContact, SRMSGMOD_T, "isFavorite", 0)) + AddContactToFavorites(hContact, NULL, NULL, NULL, 0, 0, 1, PluginConfig.g_hMenuFavorites); + if ((dwRecent = M->GetDword(hContact, "isRecent", 0)) != 0 && iIndex < nen_options.wMaxRecent) { + recentEntries[iIndex].dwTimestamp = dwRecent; + recentEntries[iIndex++].hContact = hContact; + } + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } + if (iIndex == 0) { + free(recentEntries); + return; + } + + for (i = 0; i < iIndex - 1; i++) { + for (j = 0; j < iIndex - 1; j++) { + if (recentEntries[j].dwTimestamp > recentEntries[j+1].dwTimestamp) { + rceTemp = recentEntries[j]; + recentEntries[j] = recentEntries[j+1]; + recentEntries[j+1] = rceTemp; + } + } + } + for (i = 0; i < iIndex; i++) + AddContactToFavorites(recentEntries[i].hContact, NULL, NULL, NULL, 0, 0, 1, PluginConfig.g_hMenuRecent); + + delete[] recentEntries; + } +} + -- cgit v1.2.3