summaryrefslogtreecommitdiff
path: root/plugins/TabSRMM/src/trayicon.cpp
diff options
context:
space:
mode:
authorVadim Dashevskiy <watcherhd@gmail.com>2012-05-23 07:44:30 +0000
committerVadim Dashevskiy <watcherhd@gmail.com>2012-05-23 07:44:30 +0000
commitf3d44bc057201407373012b7f682881bda7b3d98 (patch)
treeddf031a82529c84e13222131cf184ecf176d3954 /plugins/TabSRMM/src/trayicon.cpp
parentc2d827972a16f1710406d15e58304aecc4e1c9b5 (diff)
some includes restored, mir_full.sln updated, some renaming of folders and projects
git-svn-id: http://svn.miranda-ng.org/main/trunk@140 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/TabSRMM/src/trayicon.cpp')
-rw-r--r--plugins/TabSRMM/src/trayicon.cpp374
1 files changed, 374 insertions, 0 deletions
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;
+ }
+}
+