From 1babf569634e2f7cee4932cd5ccb20fe125b7a61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20P=C3=B6sel?= Date: Wed, 23 Apr 2014 14:43:51 +0000 Subject: TabSRMM: Use consistent "%s is typing..." messages as in chat and scriver git-svn-id: http://svn.miranda-ng.org/main/trunk@9056 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/TabSRMM/src/generic_msghandlers.cpp | 4110 +++++++++++++-------------- plugins/TabSRMM/src/mim.cpp | 1344 ++++----- 2 files changed, 2727 insertions(+), 2727 deletions(-) (limited to 'plugins/TabSRMM/src') diff --git a/plugins/TabSRMM/src/generic_msghandlers.cpp b/plugins/TabSRMM/src/generic_msghandlers.cpp index 776cc20cec..fc91c4e0a0 100644 --- a/plugins/TabSRMM/src/generic_msghandlers.cpp +++ b/plugins/TabSRMM/src/generic_msghandlers.cpp @@ -1,2055 +1,2055 @@ -/* - * Miranda NG: the free IM client for Microsoft* Windows* - * - * Copyright (c) 2000-09 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. - * - * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors - * - * these are generic message handlers which are used by the message dialog window procedure. - * calling them directly instead of using SendMessage() is faster. - * also contains various callback functions for custom buttons - */ - -#include "commonheaders.h" - -/** - * Save message log for given session as RTF document - */ -void TSAPI DM_SaveLogAsRTF(const TWindowData *dat) -{ - TCHAR szFilename[MAX_PATH]; - OPENFILENAME ofn = {0}; - EDITSTREAM stream = { 0 }; - TCHAR szFilter[MAX_PATH]; - - if (dat && dat->hwndIEView != 0) { - IEVIEWEVENT event = {0}; - - event.cbSize = sizeof(IEVIEWEVENT); - event.hwnd = dat->hwndIEView; - event.hContact = dat->hContact; - event.iType = IEE_SAVE_DOCUMENT; - event.dwFlags = 0; - event.count = 0; - event.codepage = 0; - CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&event); - } - else if (dat) { - TCHAR szInitialDir[MAX_PATH + 2]; - - mir_sntprintf(szFilter, SIZEOF(szFilter), _T("%s%c*.rtf%c%c"), TranslateT("Rich Edit file"), 0, 0, 0); - mir_sntprintf(szFilename, MAX_PATH, _T("%s.rtf"), dat->cache->getNick()); - - Utils::sanitizeFilename(szFilename); - - mir_sntprintf(szInitialDir, MAX_PATH, _T("%s%s\\"), M.getDataPath(), _T("\\Saved message logs")); - CreateDirectoryTreeT(szInitialDir); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = dat->hwnd; - ofn.lpstrFile = szFilename; - ofn.lpstrFilter = szFilter; - ofn.lpstrInitialDir = szInitialDir; - ofn.nMaxFile = MAX_PATH; - ofn.Flags = OFN_HIDEREADONLY; - ofn.lpstrDefExt = _T("rtf"); - if (GetSaveFileName(&ofn)) { - stream.dwCookie = (DWORD_PTR)szFilename; - stream.dwError = 0; - stream.pfnCallback = Utils::StreamOut; - SendDlgItemMessage(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_LOG : IDC_CHAT_LOG, EM_STREAMOUT, SF_RTF | SF_USECODEPAGE, (LPARAM)&stream); - } - } -} - -/** - * This is broadcasted by the container to all child windows to check if the - * container can be autohidden or -closed. - * - * wParam is the autohide timeout (in seconds) - * lParam points to a BOOL and a session which wants to prevent auto-hiding - * the container must set it to FALSE. - * - * If no session in the container disagrees, the container will be hidden. - */ -void TSAPI DM_CheckAutoHide(const TWindowData *dat, WPARAM wParam, LPARAM lParam) -{ - if (dat && lParam) { - BOOL *fResult = (BOOL *)lParam; - - if (GetWindowTextLengthA(GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_MESSAGE : IDC_CHAT_MESSAGE)) > 0) { - *fResult = FALSE; - return; // text entered in the input area -> prevent autohide/cose - } - if (dat->dwUnread) { - *fResult = FALSE; - return; // unread events, do not hide or close the container - } - if (((GetTickCount() - dat->dwLastActivity) / 1000) <= wParam) - *fResult = FALSE; // time since last activity did not yet reach the threshold. - } -} -/** - * checks if the balloon tooltip can be dismissed (usually called by - * WM_MOUSEMOVE events - */ - -void TSAPI DM_DismissTip(TWindowData *dat, const POINT& pt) -{ - if (!IsWindowVisible(dat->hwndTip)) - return; - - RECT rc; - GetWindowRect(dat->hwndTip, &rc); - if (PtInRect(&rc, pt)) - return; - - if (abs(pt.x - dat->ptTipActivation.x) > 5 || abs(pt.y - dat->ptTipActivation.y) > 5) { - SendMessage(dat->hwndTip, TTM_TRACKACTIVATE, FALSE, 0); - dat->ptTipActivation.x = dat->ptTipActivation.y = 0; - } -} - -/** - * initialize the balloon tooltip for message window notifications - */ -void TSAPI DM_InitTip(TWindowData *dat) -{ - dat->hwndTip = CreateWindowEx(0, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_BALLOON, CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, dat->hwnd, NULL, g_hInst, (LPVOID) NULL); - - ZeroMemory(&dat->ti, sizeof(dat->ti)); - dat->ti.cbSize = sizeof(dat->ti); - dat->ti.lpszText = PluginConfig.m_szNoStatus; - dat->ti.hinst = g_hInst; - dat->ti.hwnd = dat->hwnd; - dat->ti.uFlags = TTF_TRACK | TTF_IDISHWND | TTF_TRANSPARENT; - dat->ti.uId = (UINT_PTR)dat->hwnd; - SendMessage(dat->hwndTip, TTM_ADDTOOL, 0, (LPARAM)&dat->ti); - - SetWindowPos(dat->hwndTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); -} - -/** - * checks generic hotkeys valid for both IM and MUC sessions - * - * returns 1 for handled hotkeys, 0 otherwise. - */ -LRESULT TSAPI DM_GenericHotkeysCheck(MSG *message, TWindowData *dat) -{ - LRESULT mim_hotkey_check = CallService(MS_HOTKEY_CHECK, (WPARAM)message, (LPARAM)(TABSRMM_HK_SECTION_GENERIC)); - HWND hwndDlg = dat->hwnd; - - switch(mim_hotkey_check) { - case TABSRMM_HK_PASTEANDSEND: - HandlePasteAndSend(dat); - return 1; - case TABSRMM_HK_HISTORY: - SendMessage(hwndDlg, WM_COMMAND, IDC_HISTORY, 0); - return 1; - case TABSRMM_HK_CONTAINEROPTIONS: - if (dat->pContainer->hWndOptions == 0) - CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_CONTAINEROPTIONS), dat->pContainer->hwnd, - DlgProcContainerOptions, (LPARAM)dat->pContainer); - return 1; - case TABSRMM_HK_SEND: - if (!(GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MESSAGE), GWL_STYLE) & ES_READONLY)) { - PostMessage(hwndDlg, WM_COMMAND, IDOK, 0); - return 1; - } - break; - case TABSRMM_HK_TOGGLEINFOPANEL: - dat->Panel->setActive(dat->Panel->isActive() ? FALSE : TRUE); - dat->Panel->showHide(); - return 1; - case TABSRMM_HK_EMOTICONS: - SendMessage(hwndDlg, WM_COMMAND, IDC_SMILEYBTN, 0); - return 1; - case TABSRMM_HK_TOGGLETOOLBAR: - SendMessage(hwndDlg, WM_COMMAND, IDC_TOGGLETOOLBAR, 0); - return 1; - case TABSRMM_HK_CLEARLOG: - ClearLog(dat); - return 1; - case TABSRMM_HK_TOGGLESIDEBAR: - if (dat->pContainer->SideBar->isActive()) - SendMessage(hwndDlg, WM_COMMAND, IDC_TOGGLESIDEBAR, 0); - return 1; - case TABSRMM_HK_CLOSE_OTHER: - CloseOtherTabs(GetDlgItem(dat->pContainer->hwnd, IDC_MSGTABS), *dat); - return 1; - } - return 0; -} - -LRESULT TSAPI DM_MsgWindowCmdHandler(HWND hwndDlg, TContainerData *m_pContainer, TWindowData *dat, UINT cmd, WPARAM wParam, LPARAM lParam) -{ - RECT rc; - HWND hwndContainer = m_pContainer->hwnd; - int iSelection; - HMENU submenu; - - switch(cmd) { - case IDC_FONTBOLD: - case IDC_FONTITALIC: - case IDC_FONTUNDERLINE: - case IDC_FONTSTRIKEOUT: - if (dat->SendFormat != 0) { // dont use formatting if disabled - CHARFORMAT2 cf, cfOld; - ZeroMemory(&cf, sizeof(CHARFORMAT2)); - ZeroMemory(&cfOld, sizeof(CHARFORMAT2)); - cfOld.cbSize = cf.cbSize = sizeof(CHARFORMAT2); - cfOld.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_STRIKEOUT; - SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld); - BOOL isBold = (cfOld.dwEffects & CFE_BOLD) && (cfOld.dwMask & CFM_BOLD); - BOOL isItalic = (cfOld.dwEffects & CFE_ITALIC) && (cfOld.dwMask & CFM_ITALIC); - BOOL isUnderline = (cfOld.dwEffects & CFE_UNDERLINE) && (cfOld.dwMask & CFM_UNDERLINE); - BOOL isStrikeout = (cfOld.dwEffects & CFM_STRIKEOUT) && (cfOld.dwMask & CFM_STRIKEOUT); - - int cmd = LOWORD(wParam); - if (cmd == IDC_FONTBOLD && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_FONTBOLD))) - break; - if (cmd == IDC_FONTITALIC && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_FONTITALIC))) - break; - if (cmd == IDC_FONTUNDERLINE && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_FONTUNDERLINE))) - break; - if (cmd == IDC_FONTSTRIKEOUT && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_FONTSTRIKEOUT))) - break; - if (cmd == IDC_FONTBOLD) { - cf.dwEffects = isBold ? 0 : CFE_BOLD; - cf.dwMask = CFM_BOLD; - CheckDlgButton(hwndDlg, IDC_FONTBOLD, !isBold); - } else if (cmd == IDC_FONTITALIC) { - cf.dwEffects = isItalic ? 0 : CFE_ITALIC; - cf.dwMask = CFM_ITALIC; - CheckDlgButton(hwndDlg, IDC_FONTITALIC, !isItalic); - } else if (cmd == IDC_FONTUNDERLINE) { - cf.dwEffects = isUnderline ? 0 : CFE_UNDERLINE; - cf.dwMask = CFM_UNDERLINE; - CheckDlgButton(hwndDlg, IDC_FONTUNDERLINE, !isUnderline); - } else if (cmd == IDC_FONTSTRIKEOUT) { - cf.dwEffects = isStrikeout ? 0 : CFM_STRIKEOUT; - cf.dwMask = CFM_STRIKEOUT; - CheckDlgButton(hwndDlg, IDC_FONTSTRIKEOUT, !isStrikeout); - } - SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); - } - break; - - case IDC_FONTFACE: - submenu = GetSubMenu(m_pContainer->hMenuContext, 7); - { - CHARFORMAT2 cf; - ZeroMemory(&cf, sizeof(CHARFORMAT2)); - cf.cbSize = sizeof(CHARFORMAT2); - cf.dwMask = CFM_COLOR; - - GetWindowRect(GetDlgItem(hwndDlg, IDC_FONTFACE), &rc); - iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); - if (iSelection == ID_FONT_CLEARALLFORMATTING) { - cf.dwMask = CFM_BOLD | CFM_COLOR | CFM_ITALIC | CFM_UNDERLINE | CFM_STRIKEOUT; - cf.crTextColor = M.GetDword(FONTMODULE, "Font16Col", 0); - SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); - break; - } - if (iSelection == ID_FONT_DEFAULTCOLOR) { - cf.crTextColor = M.GetDword(FONTMODULE, "Font16Col", 0); - for (int i=0; i < Utils::rtf_ctable_size; i++) - if (Utils::rtf_ctable[i].clr == cf.crTextColor) - cf.crTextColor = RGB(GetRValue(cf.crTextColor), GetGValue(cf.crTextColor), GetBValue(cf.crTextColor) == 0 ? GetBValue(cf.crTextColor) + 1 : GetBValue(cf.crTextColor) - 1); - - SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); - break; - } - for (int i=0; i < RTF_CTABLE_DEFSIZE; i++) - if (Utils::rtf_ctable[i].menuid == iSelection) { - cf.crTextColor = Utils::rtf_ctable[i].clr; - SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); - } - } - break; - - case IDCANCEL: - ShowWindow(hwndContainer, SW_MINIMIZE); - return FALSE; - - case IDC_SAVE: - SendMessage(hwndDlg, WM_CLOSE, 1, 0); - break; - - case IDC_NAME: - if (GetKeyState(VK_SHIFT) & 0x8000) // copy UIN - SendMessage(hwndDlg, DM_UINTOCLIPBOARD, 0, 0); - else - CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)(dat->cache->getActiveContact()), 0); - break; - - case IDC_HISTORY: - CallService(MS_HISTORY_SHOWCONTACTHISTORY, dat->hContact, 0); - break; - - case IDC_SMILEYBTN: - if (dat->doSmileys && PluginConfig.g_SmileyAddAvail) { - MCONTACT hContact = dat->cache->getActiveContact(); - if (CheckValidSmileyPack(dat->cache->getProto(), hContact) != 0) { - SMADD_SHOWSEL3 smaddInfo = {0}; - - if (lParam == 0) - GetWindowRect(GetDlgItem(hwndDlg, IDC_SMILEYBTN), &rc); - else - GetWindowRect((HWND)lParam, &rc); - smaddInfo.cbSize = sizeof(SMADD_SHOWSEL3); - smaddInfo.hwndTarget = GetDlgItem(hwndDlg, IDC_MESSAGE); - smaddInfo.targetMessage = EM_REPLACESEL; - smaddInfo.targetWParam = TRUE; - smaddInfo.Protocolname = const_cast(dat->cache->getProto()); - smaddInfo.Direction = 0; - smaddInfo.xPosition = rc.left; - smaddInfo.yPosition = rc.top + 24; - smaddInfo.hwndParent = hwndContainer; - smaddInfo.hContact = hContact; - CallService(MS_SMILEYADD_SHOWSELECTION, (WPARAM)hwndContainer, (LPARAM)&smaddInfo); - } - } - break; - - case IDC_TIME: - submenu = GetSubMenu(m_pContainer->hMenuContext, 2); - MsgWindowUpdateMenu(dat, submenu, MENU_LOGMENU); - - GetWindowRect(GetDlgItem(hwndDlg, IDC_TIME), &rc); - - iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); - return MsgWindowMenuHandler(dat, iSelection, MENU_LOGMENU); - - case IDC_PROTOMENU: - if (dat->hContact) { - submenu = GetSubMenu(m_pContainer->hMenuContext, 4); - int iOldGlobalSendFormat = PluginConfig.m_SendFormat; - int iLocalFormat = M.GetDword(dat->hContact, "sendformat", 0); - int iNewLocalFormat = iLocalFormat; - - GetWindowRect(GetDlgItem(hwndDlg, IDC_PROTOCOL), &rc); - - CheckMenuItem(submenu, ID_MODE_GLOBAL, MF_BYCOMMAND | (!(dat->dwFlagsEx & MWF_SHOW_SPLITTEROVERRIDE) ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(submenu, ID_MODE_PRIVATE, MF_BYCOMMAND | (dat->dwFlagsEx & MWF_SHOW_SPLITTEROVERRIDE ? MF_CHECKED : MF_UNCHECKED)); - - /* - * formatting menu.. - */ - - CheckMenuItem(submenu, ID_GLOBAL_BBCODE, MF_BYCOMMAND | ((PluginConfig.m_SendFormat) ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(submenu, ID_GLOBAL_OFF, MF_BYCOMMAND | ((PluginConfig.m_SendFormat == SENDFORMAT_NONE) ? MF_CHECKED : MF_UNCHECKED)); - - CheckMenuItem(submenu, ID_THISCONTACT_GLOBALSETTING, MF_BYCOMMAND | ((iLocalFormat == SENDFORMAT_NONE) ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(submenu, ID_THISCONTACT_BBCODE, MF_BYCOMMAND | ((iLocalFormat > 0) ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(submenu, ID_THISCONTACT_OFF, MF_BYCOMMAND | ((iLocalFormat == -1) ? MF_CHECKED : MF_UNCHECKED)); - - iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); - switch (iSelection) { - case ID_MODE_GLOBAL: - dat->dwFlagsEx &= ~(MWF_SHOW_SPLITTEROVERRIDE); - db_set_b(dat->hContact, SRMSGMOD_T, "splitoverride", 0); - LoadSplitter(dat); - AdjustBottomAvatarDisplay(dat); - DM_RecalcPictureSize(dat); - SendMessage(hwndDlg, WM_SIZE, 0, 0); - break; - case ID_MODE_PRIVATE: - dat->dwFlagsEx |= MWF_SHOW_SPLITTEROVERRIDE; - db_set_b(dat->hContact, SRMSGMOD_T, "splitoverride", 1); - LoadSplitter(dat); - AdjustBottomAvatarDisplay(dat); - DM_RecalcPictureSize(dat); - SendMessage(hwndDlg, WM_SIZE, 0, 0); - break; - case ID_GLOBAL_BBCODE: - PluginConfig.m_SendFormat = SENDFORMAT_BBCODE; - break; - case ID_GLOBAL_OFF: - PluginConfig.m_SendFormat = SENDFORMAT_NONE; - break; - case ID_THISCONTACT_GLOBALSETTING: - iNewLocalFormat = 0; - break; - case ID_THISCONTACT_BBCODE: - iNewLocalFormat = SENDFORMAT_BBCODE; - break; - case ID_THISCONTACT_OFF: - iNewLocalFormat = -1; - break; - } - if (iNewLocalFormat == 0) - db_unset(dat->hContact, SRMSGMOD_T, "sendformat"); - else if (iNewLocalFormat != iLocalFormat) - db_set_dw(dat->hContact, SRMSGMOD_T, "sendformat", iNewLocalFormat); - - if (PluginConfig.m_SendFormat != iOldGlobalSendFormat) - db_set_b(0, SRMSGMOD_T, "sendformat", (BYTE)PluginConfig.m_SendFormat); - if (iNewLocalFormat != iLocalFormat || PluginConfig.m_SendFormat != iOldGlobalSendFormat) { - dat->SendFormat = M.GetDword(dat->hContact, "sendformat", PluginConfig.m_SendFormat); - if (dat->SendFormat == -1) // per contact override to disable it.. - dat->SendFormat = 0; - M.BroadcastMessage(DM_CONFIGURETOOLBAR, 0, 1); - } - } - break; - - case IDC_TOGGLETOOLBAR: - if (lParam == 1) - ApplyContainerSetting(m_pContainer, CNT_NOMENUBAR, m_pContainer->dwFlags & CNT_NOMENUBAR ? 0 : 1, true); - else - ApplyContainerSetting(m_pContainer, CNT_HIDETOOLBAR, m_pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1, true); - break; - - case IDC_INFOPANELMENU: - submenu = GetSubMenu(m_pContainer->hMenuContext, 9); - GetWindowRect(GetDlgItem(hwndDlg, IDC_NAME), &rc); - - EnableMenuItem(submenu, ID_FAVORITES_ADDCONTACTTOFAVORITES, !dat->cache->isFavorite() ? MF_ENABLED : MF_GRAYED); - EnableMenuItem(submenu, ID_FAVORITES_REMOVECONTACTFROMFAVORITES, !dat->cache->isFavorite() ? MF_GRAYED : MF_ENABLED); - - iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); - - switch(iSelection) { - case ID_FAVORITES_ADDCONTACTTOFAVORITES: - db_set_b(dat->hContact, SRMSGMOD_T, "isFavorite", 1); - AddContactToFavorites(dat->hContact, dat->cache->getNick(), dat->cache->getProto(), dat->szStatus, dat->wStatus, LoadSkinnedProtoIcon(dat->cache->getProto(), dat->cache->getStatus()), 1, PluginConfig.g_hMenuFavorites); - break; - case ID_FAVORITES_REMOVECONTACTFROMFAVORITES: - db_set_b(dat->hContact, SRMSGMOD_T, "isFavorite", 0); - DeleteMenu(PluginConfig.g_hMenuFavorites, (UINT_PTR)dat->hContact, MF_BYCOMMAND); - break; - } - dat->cache->updateFavorite(); - break; - - case IDC_SENDMENU: - submenu = GetSubMenu(m_pContainer->hMenuContext, 3); - - GetWindowRect(GetDlgItem(hwndDlg, IDOK), &rc); - CheckMenuItem(submenu, ID_SENDMENU_SENDTOMULTIPLEUSERS, MF_BYCOMMAND | (dat->sendMode & SMODE_MULTIPLE ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(submenu, ID_SENDMENU_SENDDEFAULT, MF_BYCOMMAND | (dat->sendMode == 0 ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(submenu, ID_SENDMENU_SENDTOCONTAINER, MF_BYCOMMAND | (dat->sendMode & SMODE_CONTAINER ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(submenu, ID_SENDMENU_FORCEANSISEND, MF_BYCOMMAND | (dat->sendMode & SMODE_FORCEANSI ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(submenu, ID_SENDMENU_SENDLATER, MF_BYCOMMAND | (dat->sendMode & SMODE_SENDLATER ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(submenu, ID_SENDMENU_SENDWITHOUTTIMEOUTS, MF_BYCOMMAND | (dat->sendMode & SMODE_NOACK ? MF_CHECKED : MF_UNCHECKED)); - { - const char *szFinalProto = dat->cache->getActiveProto(); - EnableMenuItem(submenu, ID_SENDMENU_SENDNUDGE, MF_BYCOMMAND | ((ProtoServiceExists(szFinalProto, PS_SEND_NUDGE) && ServiceExists(MS_NUDGE_SEND)) ? MF_ENABLED : MF_GRAYED)); - } - if (lParam) - iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); - else - iSelection = HIWORD(wParam); - - switch (iSelection) { - case ID_SENDMENU_SENDTOMULTIPLEUSERS: - dat->sendMode ^= SMODE_MULTIPLE; - if (dat->sendMode & SMODE_MULTIPLE) - HWND hwndClist = DM_CreateClist(dat); - else { - if (IsWindow(GetDlgItem(hwndDlg, IDC_CLIST))) - DestroyWindow(GetDlgItem(hwndDlg, IDC_CLIST)); - } - break; - case ID_SENDMENU_SENDNUDGE: - SendNudge(dat); - break; - case ID_SENDMENU_SENDDEFAULT: - dat->sendMode = 0; - break; - case ID_SENDMENU_SENDTOCONTAINER: - dat->sendMode ^= SMODE_CONTAINER; - RedrawWindow(hwndDlg, 0, 0, RDW_ERASENOW|RDW_UPDATENOW); - break; - case ID_SENDMENU_FORCEANSISEND: - dat->sendMode ^= SMODE_FORCEANSI; - break; - case ID_SENDMENU_SENDLATER: - if (sendLater->isAvail()) - dat->sendMode ^= SMODE_SENDLATER; - else - CWarning::show(CWarning::WARN_NO_SENDLATER, MB_OK|MB_ICONINFORMATION, TranslateT("Configuration issue|The unattended send feature is disabled. The \\b1 send later\\b0 and \\b1 send to multiple contacts\\b0 features depend on it.\n\nYou must enable it under \\b1Options->Message Sessions->Advanced tweaks\\b0. Changing this option requires a restart.")); - break; - case ID_SENDMENU_SENDWITHOUTTIMEOUTS: - dat->sendMode ^= SMODE_NOACK; - if (dat->sendMode & SMODE_NOACK) - db_set_b(dat->hContact, SRMSGMOD_T, "no_ack", 1); - else - db_unset(dat->hContact, SRMSGMOD_T, "no_ack"); - break; - } - db_set_b(dat->hContact, SRMSGMOD_T, "no_ack", (BYTE)(dat->sendMode & SMODE_NOACK ? 1 : 0)); - db_set_b(dat->hContact, SRMSGMOD_T, "forceansi", (BYTE)(dat->sendMode & SMODE_FORCEANSI ? 1 : 0)); - SetWindowPos(GetDlgItem(hwndDlg, IDC_MESSAGE), 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE); - if (dat->sendMode & SMODE_MULTIPLE || dat->sendMode & SMODE_CONTAINER) { - SetWindowPos(GetDlgItem(hwndDlg, IDC_MESSAGE), 0, 0, 0, 0, 0, SWP_DRAWFRAME|SWP_FRAMECHANGED|SWP_NOZORDER| - SWP_NOMOVE|SWP_NOSIZE|SWP_NOCOPYBITS); - RedrawWindow(hwndDlg, 0, 0, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW|RDW_ALLCHILDREN); - } - else { - if (IsWindow(GetDlgItem(hwndDlg, IDC_CLIST))) - DestroyWindow(GetDlgItem(hwndDlg, IDC_CLIST)); - SetWindowPos(GetDlgItem(hwndDlg, IDC_MESSAGE), 0, 0, 0, 0, 0, SWP_DRAWFRAME|SWP_FRAMECHANGED|SWP_NOZORDER| - SWP_NOMOVE|SWP_NOSIZE|SWP_NOCOPYBITS); - RedrawWindow(hwndDlg, 0, 0, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW|RDW_ALLCHILDREN); - } - SendMessage(hwndContainer, DM_QUERYCLIENTAREA, 0, (LPARAM)&rc); - SendMessage(hwndDlg, WM_SIZE, 0, 0); - DM_ScrollToBottom(dat, 1, 1); - Utils::showDlgControl(hwndDlg, IDC_MULTISPLITTER, (dat->sendMode & SMODE_MULTIPLE) ? SW_SHOW : SW_HIDE); - Utils::showDlgControl(hwndDlg, IDC_CLIST, (dat->sendMode & SMODE_MULTIPLE) ? SW_SHOW : SW_HIDE); - break; - - case IDC_TOGGLESIDEBAR: - SendMessage(m_pContainer->hwnd, WM_COMMAND, IDC_TOGGLESIDEBAR, 0); - break; - - case IDC_PIC: - GetClientRect(hwndDlg, &rc); - - dat->fEditNotesActive = !dat->fEditNotesActive; - if (dat->fEditNotesActive) { - int iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE)); - if (iLen != 0) { - SendMessage(hwndDlg, DM_ACTIVATETOOLTIP, IDC_MESSAGE, (LPARAM)TranslateT("You cannot edit user notes when there are unsent messages")); - dat->fEditNotesActive = false; - break; - } - - if (!dat->bIsAutosizingInput) { - dat->iSplitterSaved = dat->splitterY; - dat->splitterY = rc.bottom / 2; - SendMessage(hwndDlg, WM_SIZE, 1, 1); - } - - DBVARIANT dbv = {0}; - - if (0 == db_get_ts(dat->hContact, "UserInfo", "MyNotes", &dbv)) { - SetDlgItemText(hwndDlg, IDC_MESSAGE, dbv.ptszVal); - mir_free(dbv.ptszVal); - } - } - else { - int iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE)); - - TCHAR *buf = (TCHAR*)mir_alloc((iLen + 2) * sizeof(TCHAR)); - GetDlgItemText(hwndDlg, IDC_MESSAGE, buf, iLen + 1); - db_set_ts(dat->hContact, "UserInfo", "MyNotes", buf); - SetDlgItemText(hwndDlg, IDC_MESSAGE, _T("")); - - if (!dat->bIsAutosizingInput) { - dat->splitterY = dat->iSplitterSaved; - SendMessage(hwndDlg, WM_SIZE, 0, 0); - DM_ScrollToBottom(dat, 0, 1); - } - } - SetWindowPos(GetDlgItem(hwndDlg, IDC_MESSAGE), 0, 0, 0, 0, 0, SWP_DRAWFRAME|SWP_FRAMECHANGED|SWP_NOZORDER| - SWP_NOMOVE|SWP_NOSIZE|SWP_NOCOPYBITS); - RedrawWindow(hwndDlg, 0, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME|RDW_UPDATENOW|RDW_ALLCHILDREN); - - if (dat->fEditNotesActive) - CWarning::show(CWarning::WARN_EDITUSERNOTES, MB_OK|MB_ICONINFORMATION); - break; - - case IDM_CLEAR: - ClearLog(dat); - break; - - case IDC_PROTOCOL: - submenu = (HMENU) CallService(MS_CLIST_MENUBUILDCONTACT, dat->hContact, 0); - if (lParam == 0) - GetWindowRect(GetDlgItem(hwndDlg, IDC_PROTOCOL), &rc); - else - GetWindowRect((HWND)lParam, &rc); - - iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); - if (iSelection) - CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(iSelection), MPCF_CONTACTMENU), (LPARAM)dat->hContact); - - DestroyMenu(submenu); - break; - - // error control - case IDC_CANCELSEND: - SendMessage(hwndDlg, DM_ERRORDECIDED, MSGERROR_CANCEL, 0); - break; - - case IDC_RETRY: - SendMessage(hwndDlg, DM_ERRORDECIDED, MSGERROR_RETRY, 0); - break; - - case IDC_MSGSENDLATER: - SendMessage(hwndDlg, DM_ERRORDECIDED, MSGERROR_SENDLATER, 0); - break; - - case IDC_SELFTYPING: - if (dat->hContact) { - int iCurrentTypingMode = db_get_b(dat->hContact, SRMSGMOD, SRMSGSET_TYPING, M.GetByte(SRMSGMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW)); - - if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON && iCurrentTypingMode) { - DM_NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF); - dat->nTypeMode = PROTOTYPE_SELFTYPING_OFF; - } - db_set_b(dat->hContact, SRMSGMOD, SRMSGSET_TYPING, (BYTE)!iCurrentTypingMode); - } - break; - - default: - return 0; - } - return 1; -} - -static INT_PTR CALLBACK DlgProcAbout(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - COLORREF url_visited = RGB(128, 0, 128); - COLORREF url_unvisited = RGB(0, 0, 255); - - switch (msg) { - case WM_INITDIALOG: - TranslateDialogDefault(hwndDlg); - { - WORD v[4]; - CallService(MS_SYSTEM_GETFILEVERSION, 0, (LPARAM)&v); - - TCHAR tStr[80]; - mir_sntprintf(tStr, SIZEOF(tStr), _T("TabSRMM\n%s %d.%d.%d.%d [build %d]"), - TranslateT("Version"), __MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM, v[3]); - SetDlgItemText(hwndDlg, IDC_HEADERBAR, tStr); - } - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_MESSAGE)); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIconBig(SKINICON_EVENT_MESSAGE)); - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDOK: - case IDCANCEL: - DestroyWindow(hwndDlg); - return TRUE; - case IDC_SUPPORT: - CallService(MS_UTILS_OPENURL, 1, (LPARAM)"http://miranda.or.at/"); - break; - } - break; - - case WM_CTLCOLOREDIT: - case WM_CTLCOLORSTATIC: - SetTextColor((HDC)wParam, RGB(60, 60, 150)); - SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW)); - return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); - } - return FALSE; -} - -LRESULT TSAPI DM_ContainerCmdHandler(TContainerData *pContainer, UINT cmd, WPARAM wParam, LPARAM lParam) -{ - if (!pContainer) - return 0; - - HWND hwndDlg = pContainer->hwnd; - TWindowData *dat = (TWindowData*)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA); - - switch(cmd) { - case IDC_CLOSE: - SendMessage(hwndDlg, WM_SYSCOMMAND, SC_CLOSE, 0); - break; - case IDC_MINIMIZE: - PostMessage(hwndDlg, WM_SYSCOMMAND, SC_MINIMIZE, 0); - break; - case IDC_MAXIMIZE: - SendMessage(hwndDlg, WM_SYSCOMMAND, IsZoomed(hwndDlg) ? SC_RESTORE : SC_MAXIMIZE, 0); - break; - case IDOK: - SendMessage(pContainer->hwndActive, WM_COMMAND, wParam, lParam); // pass the IDOK command to the active child - fixes the "enter not working - break; - case ID_FILE_SAVEMESSAGELOGAS: - SendMessage(pContainer->hwndActive, DM_SAVEMESSAGELOG, 0, 0); - break; - case ID_FILE_CLOSEMESSAGESESSION: - PostMessage(pContainer->hwndActive, WM_CLOSE, 0, 1); - break; - case ID_FILE_CLOSE: - PostMessage(hwndDlg, WM_CLOSE, 0, 1); - break; - case ID_VIEW_SHOWSTATUSBAR: - ApplyContainerSetting(pContainer, CNT_NOSTATUSBAR, pContainer->dwFlags & CNT_NOSTATUSBAR ? 0 : 1, true); - break; - case ID_VIEW_VERTICALMAXIMIZE: - ApplyContainerSetting(pContainer, CNT_VERTICALMAX, pContainer->dwFlags & CNT_VERTICALMAX ? 0 : 1, false); - break; - case ID_VIEW_BOTTOMTOOLBAR: - ApplyContainerSetting(pContainer, CNT_BOTTOMTOOLBAR, pContainer->dwFlags & CNT_BOTTOMTOOLBAR ? 0 : 1, false); - M.BroadcastMessage(DM_CONFIGURETOOLBAR, 0, 1); - return 0; - case ID_VIEW_SHOWTOOLBAR: - ApplyContainerSetting(pContainer, CNT_HIDETOOLBAR, pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1, false); - M.BroadcastMessage(DM_CONFIGURETOOLBAR, 0, 1); - return 0; - case ID_VIEW_SHOWMENUBAR: - ApplyContainerSetting(pContainer, CNT_NOMENUBAR, pContainer->dwFlags & CNT_NOMENUBAR ? 0 : 1, true); - break; - case ID_VIEW_SHOWTITLEBAR: - ApplyContainerSetting(pContainer, CNT_NOTITLE, pContainer->dwFlags & CNT_NOTITLE ? 0 : 1, true); - break; - case ID_VIEW_TABSATBOTTOM: - ApplyContainerSetting(pContainer, CNT_TABSBOTTOM, pContainer->dwFlags & CNT_TABSBOTTOM ? 0 : 1, false); - break; - case ID_VIEW_SHOWMULTISENDCONTACTLIST: - SendMessage(pContainer->hwndActive, WM_COMMAND, MAKEWPARAM(IDC_SENDMENU, ID_SENDMENU_SENDTOMULTIPLEUSERS), 0); - break; - case ID_VIEW_STAYONTOP: - SendMessage(hwndDlg, WM_SYSCOMMAND, IDM_STAYONTOP, 0); - break; - case ID_CONTAINER_CONTAINEROPTIONS: - SendMessage(hwndDlg, WM_SYSCOMMAND, IDM_MOREOPTIONS, 0); - break; - case ID_EVENTPOPUPS_DISABLEALLEVENTPOPUPS: - ApplyContainerSetting(pContainer, (CNT_DONTREPORT | CNT_DONTREPORTUNFOCUSED | CNT_DONTREPORTFOCUSED | CNT_ALWAYSREPORTINACTIVE), 0, false); - return 0; - case ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISMINIMIZED: - ApplyContainerSetting(pContainer, CNT_DONTREPORT, pContainer->dwFlags & CNT_DONTREPORT ? 0 : 1, false); - return 0; - case ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISUNFOCUSED: - ApplyContainerSetting(pContainer, CNT_DONTREPORTUNFOCUSED, pContainer->dwFlags & CNT_DONTREPORTUNFOCUSED ? 0 : 1, false); - return 0; - case ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISFOCUSED: - ApplyContainerSetting(pContainer, CNT_DONTREPORTFOCUSED, pContainer->dwFlags & CNT_DONTREPORTFOCUSED ? 0 : 1, false); - return 0; - case ID_EVENTPOPUPS_SHOWPOPUPSFORALLINACTIVESESSIONS: - ApplyContainerSetting(pContainer, CNT_ALWAYSREPORTINACTIVE, pContainer->dwFlags & CNT_ALWAYSREPORTINACTIVE ? 0 : 1, false); - return 0; - case ID_WINDOWFLASHING_DISABLEFLASHING: - ApplyContainerSetting(pContainer, CNT_NOFLASH, 1, false); - ApplyContainerSetting(pContainer, CNT_FLASHALWAYS, 0, false); - return 0; - case ID_WINDOWFLASHING_FLASHUNTILFOCUSED: - ApplyContainerSetting(pContainer, CNT_NOFLASH, 0, false); - ApplyContainerSetting(pContainer, CNT_FLASHALWAYS, 1, false); - return 0; - case ID_WINDOWFLASHING_USEDEFAULTVALUES: - ApplyContainerSetting(pContainer, (CNT_NOFLASH | CNT_FLASHALWAYS), 0, false); - return 0; - case ID_OPTIONS_SAVECURRENTWINDOWPOSITIONASDEFAULT: - { - WINDOWPLACEMENT wp = {0}; - wp.length = sizeof(wp); - if (GetWindowPlacement(hwndDlg, &wp)) { - db_set_dw(0, SRMSGMOD_T, "splitx", wp.rcNormalPosition.left); - db_set_dw(0, SRMSGMOD_T, "splity", wp.rcNormalPosition.top); - db_set_dw(0, SRMSGMOD_T, "splitwidth", wp.rcNormalPosition.right - wp.rcNormalPosition.left); - db_set_dw(0, SRMSGMOD_T, "splitheight", wp.rcNormalPosition.bottom - wp.rcNormalPosition.top); - } - } - return 0; - - case ID_VIEW_INFOPANEL: - if (dat) { - RECT rc; - POINT pt; - GetWindowRect(pContainer->hwndActive, &rc); - pt.x = rc.left + 10; - pt.y = rc.top + dat->Panel->getHeight() - 10; - dat->Panel->invokeConfigDialog(pt); - } - return 0; - - /* - * commands from the message log popup will be routed to the - * message log menu handler - */ - case ID_MESSAGELOGSETTINGS_FORTHISCONTACT: - case ID_MESSAGELOGSETTINGS_GLOBAL: - if (dat) { - MsgWindowMenuHandler(dat, (int)LOWORD(wParam), MENU_LOGMENU); - return 1; - } - break; - - case ID_HELP_ABOUTTABSRMM: - CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_ABOUT), 0, DlgProcAbout, 0); - break; - - default: - return 0; // not handled - } - return 1; // handled -} - -/** - * initialize rich edit control (log and edit control) for both MUC and - * standard IM session windows. - */ -void TSAPI DM_InitRichEdit(TWindowData *dat) -{ - char *szStreamOut = NULL; - bool fIsChat = ((dat->bType == SESSIONTYPE_CHAT) ? true : false); - HWND hwndLog = GetDlgItem(dat->hwnd, !fIsChat ? IDC_LOG : IDC_CHAT_LOG); - HWND hwndEdit= GetDlgItem(dat->hwnd, !fIsChat ? IDC_MESSAGE : IDC_CHAT_MESSAGE); - HWND hwndDlg = dat->hwnd; - - dat->inputbg = fIsChat ? M.GetDword(FONTMODULE, "inputbg", SRMSGDEFSET_BKGCOLOUR) : dat->pContainer->theme.inputbg; - COLORREF colour = fIsChat ? g_Settings.crLogBackground : dat->pContainer->theme.bg; - COLORREF inputcharcolor; - - if (!fIsChat && GetWindowTextLengthA(hwndEdit) > 0) - szStreamOut = Message_GetFromStream(hwndEdit, dat, (CP_UTF8 << 16) | (SF_RTFNOOBJS | SFF_PLAINRTF | SF_USECODEPAGE)); - - SendMessage(hwndLog, EM_SETBKGNDCOLOR, 0, colour); - SendMessage(hwndEdit, EM_SETBKGNDCOLOR, 0, dat->inputbg); - - CHARFORMAT2A cf2; - ZeroMemory(&cf2, sizeof(CHARFORMAT2A)); - cf2.cbSize = sizeof(cf2); - - if (fIsChat) { - LOGFONTA lf; - LoadLogfont(MSGFONTID_MESSAGEAREA, &lf, &inputcharcolor, FONTMODULE); - - cf2.dwMask = CFM_COLOR | CFM_FACE | CFM_CHARSET | CFM_SIZE | CFM_WEIGHT | CFM_ITALIC | CFM_BACKCOLOR; - cf2.crTextColor = inputcharcolor; - cf2.bCharSet = lf.lfCharSet; - cf2.crBackColor = dat->inputbg; - strncpy(cf2.szFaceName, lf.lfFaceName, LF_FACESIZE); - cf2.dwEffects = 0; - cf2.wWeight = (WORD)lf.lfWeight; - cf2.bPitchAndFamily = lf.lfPitchAndFamily; - cf2.yHeight = abs(lf.lfHeight) * 15; - SetWindowText(hwndEdit, _T("")); - SendMessage(hwndEdit, EM_SETCHARFORMAT, 0, (LPARAM)&cf2); - } - else { - LOGFONTA lf = dat->pContainer->theme.logFonts[MSGFONTID_MESSAGEAREA]; - inputcharcolor = dat->pContainer->theme.fontColors[MSGFONTID_MESSAGEAREA]; - - for (int i=0; i < Utils::rtf_ctable_size; i++) - if (Utils::rtf_ctable[i].clr == inputcharcolor) - inputcharcolor = RGB(GetRValue(inputcharcolor), GetGValue(inputcharcolor), GetBValue(inputcharcolor) == 0 ? GetBValue(inputcharcolor) + 1 : GetBValue(inputcharcolor) - 1); - - cf2.dwMask = CFM_COLOR | CFM_FACE | CFM_CHARSET | CFM_SIZE | CFM_WEIGHT | CFM_BOLD | CFM_ITALIC; - cf2.crTextColor = inputcharcolor; - cf2.bCharSet = lf.lfCharSet; - strncpy(cf2.szFaceName, lf.lfFaceName, LF_FACESIZE); - cf2.dwEffects = ((lf.lfWeight >= FW_BOLD) ? CFE_BOLD : 0) | (lf.lfItalic ? CFE_ITALIC : 0)|(lf.lfUnderline ? CFE_UNDERLINE : 0)|(lf.lfStrikeOut ? CFE_STRIKEOUT : 0); - cf2.wWeight = (WORD)lf.lfWeight; - cf2.bPitchAndFamily = lf.lfPitchAndFamily; - cf2.yHeight = abs(lf.lfHeight) * 15; - SendMessageA(hwndEdit, EM_SETCHARFORMAT, 0, (LPARAM)&cf2); - } - - /* - * setup the rich edit control(s) - * LOG is always set to RTL, because this is needed for proper bidirectional operation later. - * The real text direction is then enforced by the streaming code which adds appropiate paragraph - * and textflow formatting commands to the - */ - - PARAFORMAT2 pf2; - ZeroMemory(&pf2, sizeof(PARAFORMAT2)); - pf2.cbSize = sizeof(pf2); - pf2.wEffects = PFE_RTLPARA; - pf2.dwMask = PFM_RTLPARA; - if (Utils::FindRTLLocale(dat)) - SendMessage(hwndEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf2); - if (!(dat->dwFlags & MWF_LOG_RTL)) { - pf2.wEffects = 0; - SendMessage(hwndEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf2); - } - SendMessage(hwndEdit, EM_SETLANGOPTIONS, 0, (LPARAM)SendMessage(hwndEdit, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD); - pf2.wEffects = PFE_RTLPARA; - pf2.dwMask |= PFM_OFFSET; - if (dat->dwFlags & MWF_INITMODE) { - pf2.dwMask |= (PFM_RIGHTINDENT | PFM_OFFSETINDENT); - pf2.dxStartIndent = 30; - pf2.dxRightIndent = 30; - } - pf2.dxOffset = dat->pContainer->theme.left_indent + 30; - if (!fIsChat) { - SetWindowText(hwndLog, _T("")); - SendMessage(hwndLog, EM_SETPARAFORMAT, 0, (LPARAM)&pf2); - SendMessage(hwndLog, EM_SETLANGOPTIONS, 0, (LPARAM)SendDlgItemMessage(hwndDlg, IDC_LOG, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD); - } - - /* - * set the scrollbars etc to RTL/LTR (only for manual RTL mode) - */ - - if (!fIsChat) { - if (dat->dwFlags & MWF_LOG_RTL) { - SetWindowLongPtr(hwndEdit, GWL_EXSTYLE, GetWindowLongPtr(hwndEdit, GWL_EXSTYLE) | WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR); - SetWindowLongPtr(hwndLog, GWL_EXSTYLE, GetWindowLongPtr(hwndLog, GWL_EXSTYLE) | WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR); - } - else { - SetWindowLongPtr(hwndEdit, GWL_EXSTYLE, GetWindowLongPtr(hwndEdit, GWL_EXSTYLE) &~(WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR)); - SetWindowLongPtr(hwndLog, GWL_EXSTYLE, GetWindowLongPtr(hwndLog, GWL_EXSTYLE) &~(WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR)); - } - SetWindowText(hwndEdit, _T("")); - } - if (szStreamOut != NULL) { - SETTEXTEX stx = {ST_DEFAULT, CP_UTF8}; - SendMessage(hwndEdit, EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)szStreamOut); - mir_free(szStreamOut); - } -} - -/* -* set the states of defined database action buttons (only if button is a toggle) -*/ - -void TSAPI DM_SetDBButtonStates(HWND hwndChild, TWindowData *dat) -{ - ButtonItem *buttonItem = dat->pContainer->buttonItems; - MCONTACT hContact = dat->hContact, hFinalContact = 0; - char *szModule, *szSetting; - HWND hwndContainer = dat->pContainer->hwnd; - - while (buttonItem) { - BOOL result = FALSE; - HWND hWnd = GetDlgItem(hwndContainer, buttonItem->uId); - - if (buttonItem->pfnCallback) - buttonItem->pfnCallback(buttonItem, hwndChild, dat, hWnd); - - if (!(buttonItem->dwFlags & BUTTON_ISTOGGLE && buttonItem->dwFlags & BUTTON_ISDBACTION)) { - buttonItem = buttonItem->nextItem; - continue; - } - szModule = buttonItem->szModule; - szSetting = buttonItem->szSetting; - if (buttonItem->dwFlags & BUTTON_DBACTIONONCONTACT || buttonItem->dwFlags & BUTTON_ISCONTACTDBACTION) { - if (hContact == 0) { - SendMessage(hWnd, BM_SETCHECK, BST_UNCHECKED, 0); - buttonItem = buttonItem->nextItem; - continue; - } - if (buttonItem->dwFlags & BUTTON_ISCONTACTDBACTION) - szModule = GetContactProto(hContact); - hFinalContact = hContact; - } else - hFinalContact = 0; - - if (buttonItem->type == DBVT_ASCIIZ) { - DBVARIANT dbv = {0}; - - if (!db_get_s(hFinalContact, szModule, szSetting, &dbv)) { - result = !strcmp((char *)buttonItem->bValuePush, dbv.pszVal); - db_free(&dbv); - } - } else { - switch (buttonItem->type) { - case DBVT_BYTE: { - BYTE val = db_get_b(hFinalContact, szModule, szSetting, 0); - result = (val == buttonItem->bValuePush[0]); - break; - } - case DBVT_WORD: { - WORD val = db_get_w(hFinalContact, szModule, szSetting, 0); - result = (val == *((WORD *) & buttonItem->bValuePush)); - break; - } - case DBVT_DWORD: { - DWORD val = db_get_dw(hFinalContact, szModule, szSetting, 0); - result = (val == *((DWORD *) & buttonItem->bValuePush)); - break; - } - } - } - SendMessage(hWnd, BM_SETCHECK, (WPARAM)result, 0); - buttonItem = buttonItem->nextItem; - } -} - -void TSAPI DM_ScrollToBottom(TWindowData *dat, WPARAM wParam, LPARAM lParam) -{ - if (dat == NULL) - return; - - if (dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED) - return; - - if ( IsIconic(dat->pContainer->hwnd)) - dat->dwFlags |= MWF_DEFERREDSCROLL; - - if (dat->hwndIEView) { - PostMessage(dat->hwnd, DM_SCROLLIEVIEW, 0, 0); - return; - } - if (dat->hwndHPP) { - SendMessage(dat->hwnd, DM_SCROLLIEVIEW, 0, 0); - return; - } - - HWND hwnd = GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_LOG : IDC_CHAT_LOG); - if (lParam) - SendMessage(hwnd, WM_SIZE, 0, 0); - - if (wParam == 1 && lParam == 1) { - RECT rc; - GetClientRect(hwnd, &rc); - int len = GetWindowTextLengthA(hwnd); - SendMessage(hwnd, EM_SETSEL, len - 1, len - 1); - } - - if (wParam) - SendMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), 0); - else - PostMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), 0); - - if (lParam) - InvalidateRect(hwnd, NULL, FALSE); -} - -static void LoadKLThread(LPVOID _param) -{ - DBVARIANT dbv; - if (!db_get_ts((MCONTACT)_param, SRMSGMOD_T, "locale", &dbv)) { - HKL hkl = LoadKeyboardLayout(dbv.ptszVal, 0); - PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_SETLOCALE, (WPARAM)_param, (LPARAM)hkl); - db_free(&dbv); - } -} - -void TSAPI DM_LoadLocale(TWindowData *dat) -{ - if (dat == NULL || !PluginConfig.m_AutoLocaleSupport) - return; - - if (dat->dwFlags & MWF_WASBACKGROUNDCREATE) - return; - - DBVARIANT dbv; - if ( !db_get_ts(dat->hContact, SRMSGMOD_T, "locale", &dbv)) - db_free(&dbv); - else { - TCHAR szKLName[KL_NAMELENGTH+1]; - if (!PluginConfig.m_dontUseDefaultKbd) { - TCHAR szBuf[20]; - GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_ILANGUAGE, szBuf, 20); - mir_sntprintf(szKLName, KL_NAMELENGTH, _T("0000%s"), szBuf); - db_set_ts(dat->hContact, SRMSGMOD_T, "locale", szKLName); - } - else { - GetKeyboardLayoutName(szKLName); - db_set_ts(dat->hContact, SRMSGMOD_T, "locale", szKLName); - } - } - - mir_forkthread(LoadKLThread, (void*)dat->hContact); -} - -LRESULT TSAPI DM_RecalcPictureSize(TWindowData *dat) -{ - if (dat) { - HBITMAP hbm = ((dat->Panel->isActive()) && dat->pContainer->avatarMode != 3) ? dat->hOwnPic : (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown); - if (hbm) { - BITMAP bminfo; - GetObject(hbm, sizeof(bminfo), &bminfo); - CalcDynamicAvatarSize(dat, &bminfo); - SendMessage(dat->hwnd, WM_SIZE, 0, 0); - } - else dat->pic.cy = dat->pic.cx = 60; - } - return 0; -} - -void TSAPI DM_UpdateLastMessage(const TWindowData *dat) -{ - if (dat == NULL) - return; - - if (dat->pContainer->hwndStatus == 0 || dat->pContainer->hwndActive != dat->hwnd) - return; - - TCHAR szBuf[100]; - if (dat->showTyping) { - SendMessage(dat->pContainer->hwndStatus, SB_SETICON, 0, (LPARAM)PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]); - mir_sntprintf(szBuf, SIZEOF(szBuf), TranslateT("%s is typing a message."), dat->cache->getNick()); - } - else { - SendMessage(dat->pContainer->hwndStatus, SB_SETICON, 0, 0); - - if (dat->pContainer->dwFlags & CNT_UINSTATUSBAR) - mir_sntprintf(szBuf, SIZEOF(szBuf), _T("UID: %s"), dat->cache->getUIN()); - else if (dat->lastMessage) { - TCHAR date[64], time[64]; - tmi.printTimeStamp(NULL, dat->lastMessage, _T("d"), date, SIZEOF(date), 0); - if (dat->pContainer->dwFlags & CNT_UINSTATUSBAR && lstrlen(date) > 6) - date[lstrlen(date) - 5] = 0; - tmi.printTimeStamp(NULL, dat->lastMessage, _T("t"), time, SIZEOF(time), 0); - mir_sntprintf(szBuf, SIZEOF(szBuf), TranslateT("Last received: %s at %s"), date, time); - } - else szBuf[0] = 0; - } - - SendMessage(dat->pContainer->hwndStatus, SB_SETTEXT, 0, (LPARAM)szBuf); -} - -/* -* save current keyboard layout for the given contact -*/ - -void TSAPI DM_SaveLocale(TWindowData *dat, WPARAM wParam, LPARAM lParam) -{ - if (!dat) - return; - - if (PluginConfig.m_AutoLocaleSupport && dat->hContact && dat->pContainer->hwndActive == dat->hwnd) { - TCHAR szKLName[KL_NAMELENGTH + 1]; - if ((HKL)lParam != dat->hkl) { - dat->hkl = (HKL)lParam; - ActivateKeyboardLayout(dat->hkl, 0); - GetKeyboardLayoutName(szKLName); - db_set_ts(dat->hContact, SRMSGMOD_T, "locale", szKLName); - GetLocaleID(dat, szKLName); - UpdateReadChars(dat); - } - } -} - -/* -* generic handler for the WM_COPY message in message log/chat history richedit control(s). -* it filters out the invisible event boundary markers from the text copied to the clipboard. -*/ - -LRESULT TSAPI DM_WMCopyHandler(HWND hwnd, WNDPROC oldWndProc, UINT msg, WPARAM wParam, LPARAM lParam) -{ - LRESULT result = mir_callNextSubclass(hwnd, oldWndProc, msg, wParam, lParam); - - if (OpenClipboard(hwnd)) { - HANDLE hClip = GetClipboardData(CF_UNICODETEXT); - if (hClip) { - HGLOBAL hgbl; - TCHAR *tszLocked; - TCHAR *tszText = (TCHAR*)mir_alloc((lstrlen((TCHAR*)hClip) + 2) * sizeof(TCHAR)); - - lstrcpy(tszText, (TCHAR*)hClip); - Utils::FilterEventMarkers(tszText); - EmptyClipboard(); - - hgbl = GlobalAlloc(GMEM_MOVEABLE, (lstrlen(tszText) + 1) * sizeof(TCHAR)); - tszLocked = (TCHAR*)GlobalLock(hgbl); - lstrcpy(tszLocked, tszText); - GlobalUnlock(hgbl); - SetClipboardData(CF_UNICODETEXT, hgbl); - if (tszText) - mir_free(tszText); - } - CloseClipboard(); - } - return result; -} - -/* -* create embedded contact list control -*/ - -HWND TSAPI DM_CreateClist(TWindowData *dat) -{ - if (!sendLater->isAvail()) { - CWarning::show(CWarning::WARN_NO_SENDLATER, MB_OK|MB_ICONINFORMATION, TranslateT("Configuration issue|The unattended send feature is disabled. The \\b1 send later\\b0 and \\b1 send to multiple contacts\\b0 features depend on it.\n\nYou must enable it under \\b1Options->Message Sessions->Advanced tweaks\\b0. Changing this option requires a restart.")); - dat->sendMode &= ~SMODE_MULTIPLE; - return 0; - } - - HWND hwndClist = CreateWindowExA(0, "CListControl", "", WS_TABSTOP | WS_VISIBLE | WS_CHILD | 0x248, - 184, 0, 30, 30, dat->hwnd, (HMENU)IDC_CLIST, g_hInst, NULL); - SendMessage(hwndClist, WM_TIMER, 14, 0); - HANDLE hItem = (HANDLE)SendMessage(hwndClist, CLM_FINDCONTACT, dat->hContact, 0); - - SetWindowLongPtr(hwndClist, GWL_EXSTYLE, GetWindowLongPtr(hwndClist, GWL_EXSTYLE) & ~CLS_EX_TRACKSELECT); - SetWindowLongPtr(hwndClist, GWL_EXSTYLE, GetWindowLongPtr(hwndClist, GWL_EXSTYLE) | (CLS_EX_NOSMOOTHSCROLLING | CLS_EX_NOTRANSLUCENTSEL)); - - if (!PluginConfig.m_AllowOfflineMultisend) - SetWindowLongPtr(hwndClist, GWL_STYLE, GetWindowLongPtr(hwndClist, GWL_STYLE) | CLS_HIDEOFFLINE); - - if (hItem) - SendMessage(hwndClist, CLM_SETCHECKMARK, (WPARAM)hItem, 1); - - if (CallService(MS_CLUI_GETCAPS, 0, 0) & CLUIF_DISABLEGROUPS && !M.GetByte("CList", "UseGroups", SETTING_USEGROUPS_DEFAULT)) - SendMessage(hwndClist, CLM_SETUSEGROUPS, FALSE, 0); - else - SendMessage(hwndClist, CLM_SETUSEGROUPS, TRUE, 0); - if (CallService(MS_CLUI_GETCAPS, 0, 0) & CLUIF_HIDEEMPTYGROUPS && M.GetByte("CList", "HideEmptyGroups", SETTING_USEGROUPS_DEFAULT)) - SendMessage(hwndClist, CLM_SETHIDEEMPTYGROUPS, TRUE, 0); - else - SendMessage(hwndClist, CLM_SETHIDEEMPTYGROUPS, FALSE, 0); - SendMessage(hwndClist, CLM_FIRST + 106, 0, 1); - SendMessage(hwndClist, CLM_AUTOREBUILD, 0, 0); - if (hwndClist) - RedrawWindow(hwndClist, 0, 0, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW); - return hwndClist; -} - -LRESULT TSAPI DM_MouseWheelHandler(HWND hwnd, HWND hwndParent, TWindowData *mwdat, WPARAM wParam, LPARAM lParam) -{ - RECT rc, rc1; - UINT uID = mwdat->bType == SESSIONTYPE_IM ? IDC_LOG : IDC_CHAT_LOG; - UINT uIDMsg = mwdat->bType == SESSIONTYPE_IM ? IDC_MESSAGE : IDC_CHAT_MESSAGE; - - POINT pt; - GetCursorPos(&pt); - GetWindowRect(hwnd, &rc); - if (PtInRect(&rc, pt)) - return 1; - - if (mwdat->pContainer->dwFlags & CNT_SIDEBAR) { - GetWindowRect(GetDlgItem(mwdat->pContainer->hwnd, IDC_SIDEBARUP), &rc); - GetWindowRect(GetDlgItem(mwdat->pContainer->hwnd, IDC_SIDEBARDOWN), &rc1); - rc.bottom = rc1.bottom; - if (PtInRect(&rc, pt)) { - short amount = (short)(HIWORD(wParam)); - SendMessage(mwdat->pContainer->hwnd, WM_COMMAND, MAKELONG(amount > 0 ? IDC_SIDEBARUP : IDC_SIDEBARDOWN, 0), (LPARAM)uIDMsg); - return 0; - } - } - if (mwdat->bType == SESSIONTYPE_CHAT) { // scroll nick list by just hovering it - RECT rcNicklist; - GetWindowRect(GetDlgItem(mwdat->hwnd, IDC_LIST), &rcNicklist); - if (PtInRect(&rcNicklist, pt)) { - SendMessage(GetDlgItem(mwdat->hwnd, IDC_LIST), WM_MOUSEWHEEL, wParam, lParam); - return 0; - } - } - if (mwdat->hwndIEView) - GetWindowRect(mwdat->hwndIEView, &rc); - else if (mwdat->hwndHPP) - GetWindowRect(mwdat->hwndHPP, &rc); - else - GetWindowRect(GetDlgItem(hwndParent, uID), &rc); - if (PtInRect(&rc, pt)) { - HWND hwnd = (mwdat->hwndIEView || mwdat->hwndHPP) ? mwdat->hwndIWebBrowserControl : GetDlgItem(hwndParent, uID); - short wDirection = (short)HIWORD(wParam); - - if (hwnd == 0) - hwnd = WindowFromPoint(pt); - - if (LOWORD(wParam) & MK_SHIFT || M.GetByte("fastscroll", 0)) { - if (wDirection < 0) - SendMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_PAGEDOWN, 0), 0); - else if (wDirection > 0) - SendMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_PAGEUP, 0), 0); - } - else SendMessage(hwnd, WM_MOUSEWHEEL, wParam, lParam); - return 0; - } - - HWND hwndTab = GetDlgItem(mwdat->pContainer->hwnd, IDC_MSGTABS); - TCHITTESTINFO hti; - GetCursorPos(&hti.pt); - ScreenToClient(hwndTab, &hti.pt); - hti.flags = 0; - if (TabCtrl_HitTest(hwndTab, &hti) != -1) { - SendMessage(hwndTab, WM_MOUSEWHEEL, wParam, -1); - return 0; - } - return 1; -} - -void TSAPI DM_FreeTheme(TWindowData *dat) -{ - if (dat) { - if (dat->hTheme) { - CloseThemeData(dat->hTheme); - dat->hTheme = 0; - } - if (dat->hThemeIP) { - CloseThemeData(dat->hThemeIP); - dat->hThemeIP = 0; - } - if (dat->hThemeToolbar) { - CloseThemeData(dat->hThemeToolbar); - dat->hThemeToolbar = 0; - } - } -} - -LRESULT TSAPI DM_ThemeChanged(TWindowData *dat) -{ - CSkinItem *item_log = &SkinItems[ID_EXTBKHISTORY]; - CSkinItem *item_msg = &SkinItems[ID_EXTBKINPUTAREA]; - - HWND hwnd = dat->hwnd; - - dat->hTheme = OpenThemeData(hwnd, L"EDIT"); - - if (dat->bType == SESSIONTYPE_IM) { - if (dat->hTheme != 0 || (CSkin::m_skinEnabled && !item_log->IGNORED)) - SetWindowLongPtr(GetDlgItem(hwnd, IDC_LOG), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwnd, IDC_LOG), GWL_EXSTYLE) & ~WS_EX_STATICEDGE); - if (dat->hTheme != 0 || (CSkin::m_skinEnabled && !item_msg->IGNORED)) - SetWindowLongPtr(GetDlgItem(hwnd, IDC_MESSAGE), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwnd, IDC_MESSAGE), GWL_EXSTYLE) & ~WS_EX_STATICEDGE); - } - else { - if (dat->hTheme != 0 || (CSkin::m_skinEnabled && !item_log->IGNORED)) { - SetWindowLongPtr(GetDlgItem(hwnd, IDC_CHAT_LOG), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwnd, IDC_CHAT_LOG), GWL_EXSTYLE) & ~WS_EX_STATICEDGE); - SetWindowLongPtr(GetDlgItem(hwnd, IDC_LIST), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwnd, IDC_LIST), GWL_EXSTYLE) & ~(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE)); - } - if (dat->hTheme != 0 || (CSkin::m_skinEnabled && !item_msg->IGNORED)) - SetWindowLongPtr(GetDlgItem(hwnd, IDC_CHAT_MESSAGE), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwnd, IDC_CHAT_MESSAGE), GWL_EXSTYLE) & ~WS_EX_STATICEDGE); - } - dat->hThemeIP = M.isAero() ? OpenThemeData(hwnd, L"ButtonStyle") : 0; - dat->hThemeToolbar = (M.isAero() || (!CSkin::m_skinEnabled && M.isVSThemed())) ? OpenThemeData(hwnd, L"REBAR") : 0; - - return 0; -} - -/** - * send out message typing notifications (MTN) when the - * user is typing/editing text in the messgae input area. - */ -void TSAPI DM_NotifyTyping(TWindowData *dat, int mode) -{ - if (!dat || !dat->hContact) - return; - - DeletePopupsForContact(dat->hContact, PU_REMOVE_ON_TYPE); - - const char *szProto = 0; - MCONTACT hContact = 0; - if (dat->bIsMeta){ - szProto = dat->cache->getActiveProto(); - hContact = dat->cache->getActiveContact(); - } - else { - szProto = dat->szProto; - hContact = dat->hContact; - } - - /* - * editing user notes or preparing a message for queued delivery -> don't send MTN - */ - if (dat->fEditNotesActive || dat->sendMode & SMODE_SENDLATER) - return; - - /* - * allow supression of sending out TN for the contact (NOTE: for metacontacts, do NOT use the subcontact handle) - */ - if (!db_get_b(dat->hContact, SRMSGMOD, SRMSGSET_TYPING, M.GetByte(SRMSGMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW))) - return; - - if (!dat->szProto) // should not, but who knows... - return; - - /* - * check status and capabilities of the protocol - */ - DWORD typeCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_4, 0); - if (!(typeCaps & PF4_SUPPORTTYPING)) - return; - - DWORD protoStatus = CallProtoService(szProto, PS_GETSTATUS, 0, 0); - if (protoStatus < ID_STATUS_ONLINE) - return; - - /* - * check visibility/invisibility lists to not "accidentially" send MTN to contacts who - * should not see them (privacy issue) - */ - DWORD protoCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0); - if (protoCaps & PF1_VISLIST && db_get_w(hContact, szProto, "ApparentMode", 0) == ID_STATUS_OFFLINE) - return; - - if (protoCaps & PF1_INVISLIST && protoStatus == ID_STATUS_INVISIBLE && db_get_w(hContact, szProto, "ApparentMode", 0) != ID_STATUS_ONLINE) - return; - - /* - * don't send to contacts which are not permanently added to the contact list, - * unless the option to ignore added status is set. - */ - if (db_get_b(dat->hContact, "CList", "NotOnList", 0) && !M.GetByte(SRMSGMOD, SRMSGSET_TYPINGUNKNOWN, SRMSGDEFSET_TYPINGUNKNOWN)) - return; - // End user check - dat->nTypeMode = mode; - CallService(MS_PROTO_SELFISTYPING, hContact, dat->nTypeMode); -} - -void TSAPI DM_OptionsApplied(TWindowData *dat, WPARAM wParam, LPARAM lParam) -{ - if (dat == 0) - return; - - HWND hwndDlg = dat->hwnd; - TContainerData *m_pContainer = dat->pContainer; - - dat->szMicroLf[0] = 0; - if (!(dat->pContainer->theme.isPrivate)) { - LoadThemeDefaults(dat->pContainer); - dat->dwFlags = dat->pContainer->theme.dwFlags; - } - LoadLocalFlags(hwndDlg, dat); - - LoadTimeZone(dat); - - dat->showUIElements = m_pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1; - - dat->dwFlagsEx = M.GetByte(dat->hContact, "splitoverride", 0) ? MWF_SHOW_SPLITTEROVERRIDE : 0; - dat->Panel->getVisibility(); - - // small inner margins (padding) for the text areas - SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0, 0)); - SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(3, 3)); - - GetSendFormat(dat, 1); - SetDialogToType(hwndDlg); - SendMessage(hwndDlg, DM_CONFIGURETOOLBAR, 0, 0); - - DM_InitRichEdit(dat); - if (hwndDlg == m_pContainer->hwndActive) - SendMessage(m_pContainer->hwnd, WM_SIZE, 0, 0); - InvalidateRect(GetDlgItem(hwndDlg, IDC_MESSAGE), NULL, FALSE); - if (!lParam) - SendMessage(hwndDlg, DM_REMAKELOG, 0, 0); - - ShowWindow(dat->hwndPanelPicParent, PluginConfig.g_bDisableAniAvatars ? SW_HIDE : SW_SHOW); - EnableWindow(dat->hwndPanelPicParent, PluginConfig.g_bDisableAniAvatars ? FALSE : TRUE); - - SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0); -} - - -void TSAPI DM_Typing(TWindowData *dat, bool fForceOff) -{ - if (dat == 0) - return; - - HWND hwndDlg = dat->hwnd; - HWND hwndContainer = dat->pContainer->hwnd; - HWND hwndStatus = dat->pContainer->hwndStatus; - - if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON && GetTickCount() - dat->nLastTyping > TIMEOUT_TYPEOFF) - DM_NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF); - - if (dat->showTyping == 1) { - if (dat->nTypeSecs > 0) { - dat->nTypeSecs--; - if (GetForegroundWindow() == hwndContainer) - SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0); - } - else { - if (!fForceOff) { - dat->showTyping = 2; - dat->nTypeSecs = 86400; - - mir_sntprintf(dat->szStatusBar, SIZEOF(dat->szStatusBar), TranslateT("%s has entered text."), dat->cache->getNick()); - if (hwndStatus && dat->pContainer->hwndActive == hwndDlg) - SendMessage(hwndStatus, SB_SETTEXT, 0, (LPARAM)dat->szStatusBar); - } - SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0); - HandleIconFeedback(dat, (HICON) - 1); - TWindowData *dat_active = (TWindowData*)GetWindowLongPtr(dat->pContainer->hwndActive, GWLP_USERDATA); - if (dat_active && dat_active->bType == SESSIONTYPE_IM) - SendMessage(hwndContainer, DM_UPDATETITLE, 0, 0); - else - SendMessage(hwndContainer, DM_UPDATETITLE, (WPARAM)dat->pContainer->hwndActive, 1); - if (!(dat->pContainer->dwFlags & CNT_NOFLASH) && PluginConfig.m_FlashOnMTN) - ReflashContainer(dat->pContainer); - } - } - else if (dat->showTyping == 2) { - if (dat->nTypeSecs > 0) - dat->nTypeSecs--; - else { - dat->szStatusBar[0] = 0; - dat->showTyping = 0; - } - UpdateStatusBar(dat); - } - else if (dat->nTypeSecs > 0) { - mir_sntprintf(dat->szStatusBar, SIZEOF(dat->szStatusBar), TranslateT("%s is typing a message."), dat->cache->getNick()); - - dat->nTypeSecs--; - if (hwndStatus && dat->pContainer->hwndActive == hwndDlg) { - SendMessage(hwndStatus, SB_SETTEXT, 0, (LPARAM)dat->szStatusBar); - SendMessage(hwndStatus, SB_SETICON, 0, (LPARAM)PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]); - } - if (IsIconic(hwndContainer) || GetForegroundWindow() != hwndContainer || GetActiveWindow() != hwndContainer) { - SetWindowText(hwndContainer, dat->szStatusBar); - dat->pContainer->dwFlags |= CNT_NEED_UPDATETITLE; - if (!(dat->pContainer->dwFlags & CNT_NOFLASH) && PluginConfig.m_FlashOnMTN) - ReflashContainer(dat->pContainer); - } - - if (dat->pContainer->hwndActive != hwndDlg) { - if (dat->mayFlashTab) - dat->iFlashIcon = PluginConfig.g_IconTypingEvent; - HandleIconFeedback(dat, PluginConfig.g_IconTypingEvent); - } - else { // active tab may show icon if status bar is disabled - if (!hwndStatus) { - if (TabCtrl_GetItemCount(GetParent(hwndDlg)) > 1 || !(dat->pContainer->dwFlags & CNT_HIDETABS)) - HandleIconFeedback(dat, PluginConfig.g_IconTypingEvent); - } - } - if ((GetForegroundWindow() != hwndContainer) || (dat->pContainer->hwndStatus == 0) || (dat->pContainer->hwndActive != hwndDlg)) - SendMessage(hwndContainer, DM_SETICON, (WPARAM)dat, (LPARAM)PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]); - - dat->showTyping = 1; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// sync splitter position for all open sessions. -// This cares about private / per container / MUC <> IM splitter syncing and everything. -// called from IM and MUC windows via DM_SPLITTERGLOBALEVENT - -int TSAPI DM_SplitterGlobalEvent(TWindowData *dat, WPARAM wParam, LPARAM lParam) -{ - RECT rcWin; - short newMessagePos; - LONG newPos; - TWindowData *srcDat = PluginConfig.lastSPlitterPos.pSrcDat; - TContainerData *srcCnt = PluginConfig.lastSPlitterPos.pSrcContainer; - bool fCntGlobal = (!dat->pContainer->settings->fPrivate ? true : false); - -#if defined(__FEAT_EXP_AUTOSPLITTER) - if (dat->bIsAutosizingInput) - return 0; -#endif - - GetWindowRect(dat->hwnd, &rcWin); - - if (wParam == 0 && lParam == 0) { - if ((dat->dwFlagsEx & MWF_SHOW_SPLITTEROVERRIDE) && dat != srcDat) - return 0; - - if (srcDat->bType == dat->bType) - newPos = PluginConfig.lastSPlitterPos.pos; - else if (srcDat->bType == SESSIONTYPE_IM && dat->bType == SESSIONTYPE_CHAT) - newPos = PluginConfig.lastSPlitterPos.pos + PluginConfig.lastSPlitterPos.off_im; - else if (srcDat->bType == SESSIONTYPE_CHAT && dat->bType == SESSIONTYPE_IM) - newPos = PluginConfig.lastSPlitterPos.pos + PluginConfig.lastSPlitterPos.off_im; - - if (dat == srcDat) { - if (dat->bType == SESSIONTYPE_IM) { - dat->pContainer->settings->splitterPos = dat->splitterY; - if (fCntGlobal) { - SaveSplitter(dat); - if (PluginConfig.lastSPlitterPos.bSync) - g_Settings.iSplitterY = dat->splitterY - DPISCALEY_S(23); - } - } - if (dat->bType == SESSIONTYPE_CHAT) { - SESSION_INFO *si = dat->si; - if (si) { - dat->pContainer->settings->splitterPos = si->iSplitterY + DPISCALEY_S(23); - if (fCntGlobal) { - g_Settings.iSplitterY = si->iSplitterY; - if (PluginConfig.lastSPlitterPos.bSync) - db_set_dw(0, SRMSGMOD_T, "splitsplity", (DWORD)si->iSplitterY + DPISCALEY_S(23)); - } - } - } - return 0; - } - - if (!fCntGlobal && dat->pContainer != srcCnt) - return 0; - if (srcCnt->settings->fPrivate && dat->pContainer != srcCnt) - return 0; - - if (!PluginConfig.lastSPlitterPos.bSync && dat->bType != srcDat->bType) - return 0; - - /* - * for inactive sessions, delay the splitter repositioning until they become - * active (faster, avoid redraw/resize problems for minimized windows) - */ - if (IsIconic(dat->pContainer->hwnd) || dat->pContainer->hwndActive != dat->hwnd) { - dat->dwFlagsEx |= MWF_EX_DELAYEDSPLITTER; - dat->wParam = newPos; - dat->lParam = PluginConfig.lastSPlitterPos.lParam; - return 0; - } - } - else newPos = wParam; - - newMessagePos = (short)rcWin.bottom - (short)newPos; - - if (dat->bType == SESSIONTYPE_IM) { - LoadSplitter(dat); - AdjustBottomAvatarDisplay(dat); - DM_RecalcPictureSize(dat); - SendMessage(dat->hwnd, WM_SIZE, 0, 0); - DM_ScrollToBottom(dat, 1,1); - if (dat != srcDat) - CSkin::UpdateToolbarBG(dat); - } - else { - SESSION_INFO *si = dat->si; - if (si) { - si->iSplitterY = g_Settings.iSplitterY; - SendMessage(dat->hwnd, WM_SIZE, 0, 0); - } - } - return 0; -} - -/** - * incoming event handler - */ - -void TSAPI DM_EventAdded(TWindowData *dat, WPARAM wParam, LPARAM lParam) -{ - TContainerData *m_pContainer = dat->pContainer; - DWORD dwTimestamp = 0; - HWND hwndDlg = dat->hwnd, hwndContainer = m_pContainer->hwnd, hwndTab = GetParent(dat->hwnd); - HANDLE hDbEvent = (HANDLE)lParam; - - DBEVENTINFO dbei = { sizeof(dbei) }; - db_event_get(hDbEvent, &dbei); - if (dat->hDbEventFirst == NULL) - dat->hDbEventFirst = hDbEvent; - - BOOL bIsStatusChangeEvent = IsStatusEvent(dbei.eventType); - - if (dbei.eventType == EVENTTYPE_MESSAGE && (dbei.flags & DBEF_READ)) - return; - - if (!DbEventIsShown(dat, &dbei)) - return; - - if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & (DBEF_SENT))) { - dat->lastMessage = dbei.timestamp; - dat->szStatusBar[0] = 0; - if (dat->showTyping) { - dat->nTypeSecs = 0; - DM_Typing(dat, true); - dat->showTyping = 0; - } - HandleIconFeedback(dat, (HICON)-1); - if (m_pContainer->hwndStatus) - PostMessage(hwndDlg, DM_UPDATELASTMESSAGE, 0, 0); - } - /* - * set the message log divider to mark new (maybe unseen) messages, if the container has - * been minimized or in the background. - */ - if (!(dbei.flags & DBEF_SENT) && !bIsStatusChangeEvent) { - if (PluginConfig.m_DividersUsePopupConfig && PluginConfig.m_UseDividers) { - if (!MessageWindowOpened(dat->hContact, 0)) - SendMessage(hwndDlg, DM_ADDDIVIDER, 0, 0); - } - else if (PluginConfig.m_UseDividers) { - if ((GetForegroundWindow() != hwndContainer || GetActiveWindow() != hwndContainer)) - SendMessage(hwndDlg, DM_ADDDIVIDER, 0, 0); - else { - if (m_pContainer->hwndActive != hwndDlg) - SendMessage(hwndDlg, DM_ADDDIVIDER, 0, 0); - } - } - tabSRMM_ShowPopup(wParam, hDbEvent, dbei.eventType, m_pContainer->fHidden ? 0 : 1, m_pContainer, hwndDlg, dat->cache->getActiveProto(), dat); - if (IsWindowVisible(m_pContainer->hwnd)) - m_pContainer->fHidden = false; - } - dat->cache->updateStats(TSessionStats::UPDATE_WITH_LAST_RCV, 0); - - if (hDbEvent != dat->hDbEventFirst) { - HANDLE nextEvent = db_event_next(dat->hContact, hDbEvent); - if (1 || nextEvent == 0) { - if (!(dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED)) - SendMessage(hwndDlg, DM_APPENDTOLOG, lParam, 0); - else { - TCHAR szBuf[100]; - - if (dat->iNextQueuedEvent >= dat->iEventQueueSize) { - dat->hQueuedEvents = (HANDLE*)mir_realloc(dat->hQueuedEvents, (dat->iEventQueueSize + 10) * sizeof(HANDLE)); - dat->iEventQueueSize += 10; - } - dat->hQueuedEvents[dat->iNextQueuedEvent++] = hDbEvent; - mir_sntprintf(szBuf, SIZEOF(szBuf), TranslateT("Autoscrolling is disabled, %d message(s) queued (press F12 to enable it)"), - dat->iNextQueuedEvent); - SetDlgItemText(hwndDlg, IDC_LOGFROZENTEXT, szBuf); - RedrawWindow(GetDlgItem(hwndDlg, IDC_LOGFROZENTEXT), NULL, NULL, RDW_INVALIDATE); - } - } - else SendMessage(hwndDlg, DM_REMAKELOG, 0, 0); - } - else SendMessage(hwndDlg, DM_REMAKELOG, 0, 0); - - // handle tab flashing - if ((TabCtrl_GetCurSel(hwndTab) != dat->iTabID) && !(dbei.flags & DBEF_SENT) && !bIsStatusChangeEvent) { - switch (dbei.eventType) { - case EVENTTYPE_MESSAGE: - dat->iFlashIcon = PluginConfig.g_IconMsgEvent; - break; - case EVENTTYPE_FILE: - dat->iFlashIcon = PluginConfig.g_IconFileEvent; - break; - default: - dat->iFlashIcon = PluginConfig.g_IconMsgEvent; - break; - } - SetTimer(hwndDlg, TIMERID_FLASHWND, TIMEOUT_FLASHWND, NULL); - dat->mayFlashTab = TRUE; - } - /* - * try to flash the contact list... - */ - FlashOnClist(hwndDlg, dat, hDbEvent, &dbei); - - /* - * autoswitch tab if option is set AND container is minimized (otherwise, we never autoswitch) - * never switch for status changes... - */ - if (!(dbei.flags & DBEF_SENT) && !bIsStatusChangeEvent) { - if (PluginConfig.haveAutoSwitch() && m_pContainer->hwndActive != hwndDlg) { - if ((IsIconic(hwndContainer) && !IsZoomed(hwndContainer)) || (PluginConfig.m_HideOnClose && !IsWindowVisible(m_pContainer->hwnd))) { - int iItem = GetTabIndexFromHWND(GetParent(hwndDlg), hwndDlg); - if (iItem >= 0) { - TabCtrl_SetCurSel(GetParent(hwndDlg), iItem); - ShowWindow(m_pContainer->hwndActive, SW_HIDE); - m_pContainer->hwndActive = hwndDlg; - SendMessage(hwndContainer, DM_UPDATETITLE, dat->hContact, 0); - m_pContainer->dwFlags |= CNT_DEFERREDTABSELECT; - } - } - } - } - - /* - * flash window if it is not focused - */ - if ((GetActiveWindow() != hwndContainer || GetForegroundWindow() != hwndContainer || dat->pContainer->hwndActive != hwndDlg) && !(dbei.flags & DBEF_SENT) && !bIsStatusChangeEvent) { - if (!(m_pContainer->dwFlags & CNT_NOFLASH) && (GetActiveWindow() != hwndContainer || GetForegroundWindow() != hwndContainer)) - FlashContainer(m_pContainer, 1, 0); - SendMessage(hwndContainer, DM_SETICON, (WPARAM)dat, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_MESSAGE)); - m_pContainer->dwFlags |= CNT_NEED_UPDATETITLE; - } - - /* - * play a sound - */ - if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & (DBEF_SENT))) - PostMessage(hwndDlg, DM_PLAYINCOMINGSOUND, 0, 0); - - if (dat->pWnd) - dat->pWnd->Invalidate(); -} - -void TSAPI DM_HandleAutoSizeRequest(TWindowData *dat, REQRESIZE* rr) -{ - if (dat == NULL || rr == NULL || GetForegroundWindow() != dat->pContainer->hwnd) - return; - - if (!dat->bIsAutosizingInput || dat->iInputAreaHeight == -1) - return; - - LONG heightLimit = M.GetDword("autoSplitMinLimit", 0); - LONG iNewHeight = rr->rc.bottom - rr->rc.top; - - if (CSkin::m_skinEnabled && !SkinItems[ID_EXTBKINPUTAREA].IGNORED) - iNewHeight += (SkinItems[ID_EXTBKINPUTAREA].MARGIN_TOP + SkinItems[ID_EXTBKINPUTAREA].MARGIN_BOTTOM - 2); - - if (heightLimit && iNewHeight < heightLimit) - iNewHeight = heightLimit; - - if (iNewHeight == dat->iInputAreaHeight) - return; - - RECT rc; - GetClientRect(dat->hwnd, &rc); - LONG cy = rc.bottom - rc.top; - LONG panelHeight = (dat->Panel->isActive() ? dat->Panel->getHeight() : 0); - - if (iNewHeight > (cy - panelHeight) / 2) - iNewHeight = (cy - panelHeight) / 2; - - if (dat->bType == SESSIONTYPE_IM) { - dat->dynaSplitter = rc.bottom - (rc.bottom - iNewHeight + DPISCALEY_S(2)); - if (dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR) - dat->dynaSplitter += DPISCALEY_S(22); - dat->splitterY = dat->dynaSplitter + DPISCALEY_S(34); - DM_RecalcPictureSize(dat); - } - else if (dat->si) { - dat->si->iSplitterY = (rc.bottom - (rc.bottom - iNewHeight + DPISCALEY_S(3))) + DPISCALEY_S(34); - if (!(dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR)) - dat->si->iSplitterY -= DPISCALEY_S(22); - SendMessage(dat->hwnd, WM_SIZE, 0, 0); - } - dat->iInputAreaHeight = iNewHeight; - CSkin::UpdateToolbarBG(dat); - DM_ScrollToBottom(dat, 1, 0); -} - -void TSAPI DM_UpdateTitle(TWindowData *dat, WPARAM wParam, LPARAM lParam) -{ - TCHAR newtitle[128], newcontactname[128]; - DWORD dwOldIdle = dat->idle; - const char *szActProto = 0; - - HWND hwndDlg = dat->hwnd; - HWND hwndTab = GetParent(hwndDlg); - HWND hwndContainer = dat->pContainer->hwnd; - TContainerData* m_pContainer = dat->pContainer; - - newcontactname[0] = 0; - dat->szStatus[0] = 0; - - if (dat->iTabID == -1) - return; - - TCITEM item = { 0 }; - - if (dat->hContact) { - const TCHAR *szNick = dat->cache->getNick(); - - if (dat->szProto) { - szActProto = dat->cache->getProto(); - MCONTACT hActContact = dat->hContact; - - bool bHasName = (dat->cache->getUIN()[0] != 0); - dat->idle = dat->cache->getIdleTS(); - dat->dwFlagsEx = dat->idle ? dat->dwFlagsEx | MWF_SHOW_ISIDLE : dat->dwFlagsEx & ~MWF_SHOW_ISIDLE; - - dat->wStatus = dat->cache->getStatus(); - _tcsncpy_s(dat->szStatus, SIZEOF(dat->szStatus), pcli->pfnGetStatusModeDescription(dat->szProto == NULL ? ID_STATUS_OFFLINE : dat->wStatus, 0), _TRUNCATE); - - if (lParam != 0) { - if (PluginConfig.m_CutContactNameOnTabs) - CutContactName(szNick, newcontactname, SIZEOF(newcontactname)); - else - lstrcpyn(newcontactname, szNick, SIZEOF(newcontactname)); - - Utils::DoubleAmpersands(newcontactname); - - if (lstrlen(newcontactname) != 0 && dat->szStatus != NULL) { - if (PluginConfig.m_StatusOnTabs) - mir_sntprintf(newtitle, 127, _T("%s (%s)"), newcontactname, dat->szStatus); - else - mir_sntprintf(newtitle, 127, _T("%s"), newcontactname); - } - else mir_sntprintf(newtitle, 127, _T("%s"), _T("Forward")); - - item.mask |= TCIF_TEXT; - } - SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0); - - TCHAR fulluin[256]; - if (dat->bIsMeta) - mir_sntprintf(fulluin, SIZEOF(fulluin), - TranslateT("UID: %s (SHIFT click -> copy to clipboard)\nClick for User's Details\nRight click for MetaContact control\nClick dropdown to add or remove user from your favorites."), - bHasName ? dat->cache->getUIN() : TranslateT("No UID")); - else - mir_sntprintf(fulluin, SIZEOF(fulluin), - TranslateT("UID: %s (SHIFT click -> copy to clipboard)\nClick for User's Details\nClick dropdown to change this contact's favorite status."), - bHasName ? dat->cache->getUIN() : TranslateT("No UID")); - - SendMessage(GetDlgItem(hwndDlg, IDC_NAME), BUTTONADDTOOLTIP, (WPARAM)fulluin, BATF_TCHAR); - } - } - else lstrcpyn(newtitle, _T("Message Session"), SIZEOF(newtitle)); - - if (dat->idle != dwOldIdle || lParam != 0) { - if (item.mask & TCIF_TEXT) { - item.pszText = newtitle; - _tcsncpy(dat->newtitle, newtitle, SIZEOF(dat->newtitle)); - dat->newtitle[127] = 0; - item.cchTextMax = 127; - if (dat->pWnd) - dat->pWnd->updateTitle(dat->cache->getNick()); - } - if (dat->iTabID >= 0) { - TabCtrl_SetItem(hwndTab, dat->iTabID, &item); - if (m_pContainer->dwFlags & CNT_SIDEBAR) - m_pContainer->SideBar->updateSession(dat); - } - if (m_pContainer->hwndActive == hwndDlg && lParam) - SendMessage(hwndContainer, DM_UPDATETITLE, dat->hContact, 0); - - UpdateTrayMenuState(dat, TRUE); - if (dat->cache->isFavorite()) - AddContactToFavorites(dat->hContact, dat->cache->getNick(), szActProto, dat->szStatus, dat->wStatus, - LoadSkinnedProtoIcon(dat->cache->getProto(), dat->cache->getStatus()), 0, PluginConfig.g_hMenuFavorites); - - if (dat->cache->isRecent()) - AddContactToFavorites(dat->hContact, dat->cache->getNick(), szActProto, dat->szStatus, dat->wStatus, - LoadSkinnedProtoIcon(dat->cache->getProto(), dat->cache->getStatus()), 0, PluginConfig.g_hMenuRecent); - - dat->Panel->Invalidate(); - if (dat->pWnd) - dat->pWnd->Invalidate(); - - if (PluginConfig.g_FlashAvatarAvail) { - FLASHAVATAR fa = {0}; - - fa.hContact = dat->hContact; - fa.hWindow = 0; - fa.id = 25367; - fa.cProto = dat->szProto; - - CallService(MS_FAVATAR_GETINFO, (WPARAM)&fa, 0); - dat->hwndFlash = fa.hWindow; - if (dat->hwndFlash) - SetParent(dat->hwndFlash, dat->Panel->isActive() ? dat->hwndPanelPicParent : GetDlgItem(hwndDlg, IDC_CONTACTPIC)); - } - } - // care about MetaContacts and update the statusbar icon with the currently "most online" contact... - if (dat->bIsMeta) { - PostMessage(hwndDlg, DM_UPDATEMETACONTACTINFO, 0, 0); - PostMessage(hwndDlg, DM_OWNNICKCHANGED, 0, 0); - if (m_pContainer->dwFlags & CNT_UINSTATUSBAR) - DM_UpdateLastMessage(dat); - } -} - -/* -* status icon stuff (by sje, used for indicating encryption status in the status bar -* this is now part of the message window api -*/ - -static HANDLE hHookIconPressedEvt; - -static int OnSrmmIconChanged(WPARAM hContact, LPARAM) -{ - if (hContact == NULL) - M.BroadcastMessage(DM_STATUSICONCHANGE, 0, 0); - else { - HWND hwnd = M.FindWindow(hContact); - if (hwnd) - PostMessage(hwnd, DM_STATUSICONCHANGE, 0, 0); - } - return 0; -} - -void DrawStatusIcons(TWindowData *dat, HDC hDC, RECT r, int gap) -{ - HICON hIcon = NULL; - int x = r.left; - LONG cx_icon = PluginConfig.m_smcxicon; - LONG cy_icon = PluginConfig.m_smcyicon; - LONG y = (r.top + r.bottom - cx_icon) >> 1; - - SetBkMode(hDC, TRANSPARENT); - - int nIcon = 0; - while (StatusIconData *si = Srmm_GetNthIcon(dat->hContact, nIcon++)) { - if ( !strcmp(si->szModule, MSG_ICON_MODULE)) { - if (si->dwId == MSG_ICON_SOUND) { - DrawIconEx(hDC, x, y, PluginConfig.g_buttonBarIcons[ICON_DEFAULT_SOUNDS], - cx_icon, cy_icon, 0, NULL, DI_NORMAL); - - DrawIconEx(hDC, x, y, dat->pContainer->dwFlags & CNT_NOSOUND ? - PluginConfig.g_iconOverlayDisabled : PluginConfig.g_iconOverlayEnabled, - cx_icon, cy_icon, 0, NULL, DI_NORMAL); - } - else if (si->dwId == MSG_ICON_UTN) { - if (dat->bType == SESSIONTYPE_IM) { - DrawIconEx(hDC, x, y, PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING], cx_icon, cy_icon, 0, NULL, DI_NORMAL); - - DrawIconEx(hDC, x, y, db_get_b(dat->hContact, SRMSGMOD, SRMSGSET_TYPING, M.GetByte(SRMSGMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW)) ? - PluginConfig.g_iconOverlayEnabled : PluginConfig.g_iconOverlayDisabled, cx_icon, cy_icon, 0, NULL, DI_NORMAL); - } - else CSkin::DrawDimmedIcon(hDC, x, y, cx_icon, cy_icon, PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING], 50); - } - else if (si->dwId == MSG_ICON_SESSION) { - DrawIconEx(hDC, x, y, PluginConfig.g_sideBarIcons[0], cx_icon, cy_icon, 0, NULL, DI_NORMAL); - } - } - else { - if ((si->flags & MBF_DISABLED) && si->hIconDisabled) - hIcon = si->hIconDisabled; - else - hIcon = si->hIcon; - - if ((si->flags & MBF_DISABLED) && si->hIconDisabled == NULL) - CSkin::DrawDimmedIcon(hDC, x, y, cx_icon, cy_icon, hIcon, 50); - else - DrawIconEx(hDC, x, y, hIcon, 16, 16, 0, NULL, DI_NORMAL); - } - - x += cx_icon + gap; - } -} - -void SI_CheckStatusIconClick(TWindowData *dat, HWND hwndFrom, POINT pt, RECT r, int gap, int code) -{ - if (dat && (code == NM_CLICK || code == NM_RCLICK)) { - POINT ptScreen; - GetCursorPos(&ptScreen); - if (!PtInRect(&rcLastStatusBarClick, ptScreen)) - return; - } - - UINT iconNum = (pt.x - (r.left + 0)) / (PluginConfig.m_smcxicon + gap), list_icons = 0; - StatusIconData *si = Srmm_GetNthIcon((dat) ? dat->hContact : 0, iconNum); - if (si == NULL) - return; - - if ( !strcmp(si->szModule, MSG_ICON_MODULE)) { - if (si->dwId == MSG_ICON_SOUND && code != NM_RCLICK) { - if (GetKeyState(VK_SHIFT) & 0x8000) { - for (TContainerData *p = pFirstContainer; p; p = p->pNext) { - p->dwFlags = ((dat->pContainer->dwFlags & CNT_NOSOUND) ? p->dwFlags | CNT_NOSOUND : p->dwFlags & ~CNT_NOSOUND); - InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE); - } - } - else { - dat->pContainer->dwFlags ^= CNT_NOSOUND; - InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE); - } - } - else if (si->dwId == MSG_ICON_UTN && code != NM_RCLICK && dat->bType == SESSIONTYPE_IM) { - SendMessage(dat->pContainer->hwndActive, WM_COMMAND, IDC_SELFTYPING, 0); - InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE); - } - else if (si->dwId == MSG_ICON_SESSION) { - if (code == NM_CLICK) - PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_TRAYICONNOTIFY, 101, WM_LBUTTONUP); - else if (code == NM_RCLICK) - PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_TRAYICONNOTIFY, 101, WM_RBUTTONUP); - } - } - else { - StatusIconClickData sicd = { sizeof(sicd) }; - GetCursorPos(&sicd.clickLocation); - sicd.dwId = si->dwId; - sicd.szModule = si->szModule; - sicd.flags = (code == NM_RCLICK ? MBCF_RIGHTBUTTON : 0); - NotifyEventHooks(hHookIconPressedEvt, dat->hContact, (LPARAM)&sicd); - InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE); - } -} - -int SI_InitStatusIcons() -{ - StatusIconData sid = { sizeof(sid) }; - sid.szModule = MSG_ICON_MODULE; - sid.dwId = MSG_ICON_SOUND; // Sounds - Srmm_AddIcon(&sid); - - sid.dwId = MSG_ICON_UTN; - Srmm_AddIcon(&sid); - - sid.dwId = MSG_ICON_SESSION; - Srmm_AddIcon(&sid); - - HookEvent(ME_MSG_ICONSCHANGED, OnSrmmIconChanged); - - hHookIconPressedEvt = CreateHookableEvent(ME_MSG_ICONPRESSED); - return 0; -} - -int SI_DeinitStatusIcons() -{ - DestroyHookableEvent(hHookIconPressedEvt); - return 0; -} +/* + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright (c) 2000-09 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. + * + * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors + * + * these are generic message handlers which are used by the message dialog window procedure. + * calling them directly instead of using SendMessage() is faster. + * also contains various callback functions for custom buttons + */ + +#include "commonheaders.h" + +/** + * Save message log for given session as RTF document + */ +void TSAPI DM_SaveLogAsRTF(const TWindowData *dat) +{ + TCHAR szFilename[MAX_PATH]; + OPENFILENAME ofn = {0}; + EDITSTREAM stream = { 0 }; + TCHAR szFilter[MAX_PATH]; + + if (dat && dat->hwndIEView != 0) { + IEVIEWEVENT event = {0}; + + event.cbSize = sizeof(IEVIEWEVENT); + event.hwnd = dat->hwndIEView; + event.hContact = dat->hContact; + event.iType = IEE_SAVE_DOCUMENT; + event.dwFlags = 0; + event.count = 0; + event.codepage = 0; + CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&event); + } + else if (dat) { + TCHAR szInitialDir[MAX_PATH + 2]; + + mir_sntprintf(szFilter, SIZEOF(szFilter), _T("%s%c*.rtf%c%c"), TranslateT("Rich Edit file"), 0, 0, 0); + mir_sntprintf(szFilename, MAX_PATH, _T("%s.rtf"), dat->cache->getNick()); + + Utils::sanitizeFilename(szFilename); + + mir_sntprintf(szInitialDir, MAX_PATH, _T("%s%s\\"), M.getDataPath(), _T("\\Saved message logs")); + CreateDirectoryTreeT(szInitialDir); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = dat->hwnd; + ofn.lpstrFile = szFilename; + ofn.lpstrFilter = szFilter; + ofn.lpstrInitialDir = szInitialDir; + ofn.nMaxFile = MAX_PATH; + ofn.Flags = OFN_HIDEREADONLY; + ofn.lpstrDefExt = _T("rtf"); + if (GetSaveFileName(&ofn)) { + stream.dwCookie = (DWORD_PTR)szFilename; + stream.dwError = 0; + stream.pfnCallback = Utils::StreamOut; + SendDlgItemMessage(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_LOG : IDC_CHAT_LOG, EM_STREAMOUT, SF_RTF | SF_USECODEPAGE, (LPARAM)&stream); + } + } +} + +/** + * This is broadcasted by the container to all child windows to check if the + * container can be autohidden or -closed. + * + * wParam is the autohide timeout (in seconds) + * lParam points to a BOOL and a session which wants to prevent auto-hiding + * the container must set it to FALSE. + * + * If no session in the container disagrees, the container will be hidden. + */ +void TSAPI DM_CheckAutoHide(const TWindowData *dat, WPARAM wParam, LPARAM lParam) +{ + if (dat && lParam) { + BOOL *fResult = (BOOL *)lParam; + + if (GetWindowTextLengthA(GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_MESSAGE : IDC_CHAT_MESSAGE)) > 0) { + *fResult = FALSE; + return; // text entered in the input area -> prevent autohide/cose + } + if (dat->dwUnread) { + *fResult = FALSE; + return; // unread events, do not hide or close the container + } + if (((GetTickCount() - dat->dwLastActivity) / 1000) <= wParam) + *fResult = FALSE; // time since last activity did not yet reach the threshold. + } +} +/** + * checks if the balloon tooltip can be dismissed (usually called by + * WM_MOUSEMOVE events + */ + +void TSAPI DM_DismissTip(TWindowData *dat, const POINT& pt) +{ + if (!IsWindowVisible(dat->hwndTip)) + return; + + RECT rc; + GetWindowRect(dat->hwndTip, &rc); + if (PtInRect(&rc, pt)) + return; + + if (abs(pt.x - dat->ptTipActivation.x) > 5 || abs(pt.y - dat->ptTipActivation.y) > 5) { + SendMessage(dat->hwndTip, TTM_TRACKACTIVATE, FALSE, 0); + dat->ptTipActivation.x = dat->ptTipActivation.y = 0; + } +} + +/** + * initialize the balloon tooltip for message window notifications + */ +void TSAPI DM_InitTip(TWindowData *dat) +{ + dat->hwndTip = CreateWindowEx(0, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_BALLOON, CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, dat->hwnd, NULL, g_hInst, (LPVOID) NULL); + + ZeroMemory(&dat->ti, sizeof(dat->ti)); + dat->ti.cbSize = sizeof(dat->ti); + dat->ti.lpszText = PluginConfig.m_szNoStatus; + dat->ti.hinst = g_hInst; + dat->ti.hwnd = dat->hwnd; + dat->ti.uFlags = TTF_TRACK | TTF_IDISHWND | TTF_TRANSPARENT; + dat->ti.uId = (UINT_PTR)dat->hwnd; + SendMessage(dat->hwndTip, TTM_ADDTOOL, 0, (LPARAM)&dat->ti); + + SetWindowPos(dat->hwndTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); +} + +/** + * checks generic hotkeys valid for both IM and MUC sessions + * + * returns 1 for handled hotkeys, 0 otherwise. + */ +LRESULT TSAPI DM_GenericHotkeysCheck(MSG *message, TWindowData *dat) +{ + LRESULT mim_hotkey_check = CallService(MS_HOTKEY_CHECK, (WPARAM)message, (LPARAM)(TABSRMM_HK_SECTION_GENERIC)); + HWND hwndDlg = dat->hwnd; + + switch(mim_hotkey_check) { + case TABSRMM_HK_PASTEANDSEND: + HandlePasteAndSend(dat); + return 1; + case TABSRMM_HK_HISTORY: + SendMessage(hwndDlg, WM_COMMAND, IDC_HISTORY, 0); + return 1; + case TABSRMM_HK_CONTAINEROPTIONS: + if (dat->pContainer->hWndOptions == 0) + CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_CONTAINEROPTIONS), dat->pContainer->hwnd, + DlgProcContainerOptions, (LPARAM)dat->pContainer); + return 1; + case TABSRMM_HK_SEND: + if (!(GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MESSAGE), GWL_STYLE) & ES_READONLY)) { + PostMessage(hwndDlg, WM_COMMAND, IDOK, 0); + return 1; + } + break; + case TABSRMM_HK_TOGGLEINFOPANEL: + dat->Panel->setActive(dat->Panel->isActive() ? FALSE : TRUE); + dat->Panel->showHide(); + return 1; + case TABSRMM_HK_EMOTICONS: + SendMessage(hwndDlg, WM_COMMAND, IDC_SMILEYBTN, 0); + return 1; + case TABSRMM_HK_TOGGLETOOLBAR: + SendMessage(hwndDlg, WM_COMMAND, IDC_TOGGLETOOLBAR, 0); + return 1; + case TABSRMM_HK_CLEARLOG: + ClearLog(dat); + return 1; + case TABSRMM_HK_TOGGLESIDEBAR: + if (dat->pContainer->SideBar->isActive()) + SendMessage(hwndDlg, WM_COMMAND, IDC_TOGGLESIDEBAR, 0); + return 1; + case TABSRMM_HK_CLOSE_OTHER: + CloseOtherTabs(GetDlgItem(dat->pContainer->hwnd, IDC_MSGTABS), *dat); + return 1; + } + return 0; +} + +LRESULT TSAPI DM_MsgWindowCmdHandler(HWND hwndDlg, TContainerData *m_pContainer, TWindowData *dat, UINT cmd, WPARAM wParam, LPARAM lParam) +{ + RECT rc; + HWND hwndContainer = m_pContainer->hwnd; + int iSelection; + HMENU submenu; + + switch(cmd) { + case IDC_FONTBOLD: + case IDC_FONTITALIC: + case IDC_FONTUNDERLINE: + case IDC_FONTSTRIKEOUT: + if (dat->SendFormat != 0) { // dont use formatting if disabled + CHARFORMAT2 cf, cfOld; + ZeroMemory(&cf, sizeof(CHARFORMAT2)); + ZeroMemory(&cfOld, sizeof(CHARFORMAT2)); + cfOld.cbSize = cf.cbSize = sizeof(CHARFORMAT2); + cfOld.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_STRIKEOUT; + SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld); + BOOL isBold = (cfOld.dwEffects & CFE_BOLD) && (cfOld.dwMask & CFM_BOLD); + BOOL isItalic = (cfOld.dwEffects & CFE_ITALIC) && (cfOld.dwMask & CFM_ITALIC); + BOOL isUnderline = (cfOld.dwEffects & CFE_UNDERLINE) && (cfOld.dwMask & CFM_UNDERLINE); + BOOL isStrikeout = (cfOld.dwEffects & CFM_STRIKEOUT) && (cfOld.dwMask & CFM_STRIKEOUT); + + int cmd = LOWORD(wParam); + if (cmd == IDC_FONTBOLD && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_FONTBOLD))) + break; + if (cmd == IDC_FONTITALIC && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_FONTITALIC))) + break; + if (cmd == IDC_FONTUNDERLINE && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_FONTUNDERLINE))) + break; + if (cmd == IDC_FONTSTRIKEOUT && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_FONTSTRIKEOUT))) + break; + if (cmd == IDC_FONTBOLD) { + cf.dwEffects = isBold ? 0 : CFE_BOLD; + cf.dwMask = CFM_BOLD; + CheckDlgButton(hwndDlg, IDC_FONTBOLD, !isBold); + } else if (cmd == IDC_FONTITALIC) { + cf.dwEffects = isItalic ? 0 : CFE_ITALIC; + cf.dwMask = CFM_ITALIC; + CheckDlgButton(hwndDlg, IDC_FONTITALIC, !isItalic); + } else if (cmd == IDC_FONTUNDERLINE) { + cf.dwEffects = isUnderline ? 0 : CFE_UNDERLINE; + cf.dwMask = CFM_UNDERLINE; + CheckDlgButton(hwndDlg, IDC_FONTUNDERLINE, !isUnderline); + } else if (cmd == IDC_FONTSTRIKEOUT) { + cf.dwEffects = isStrikeout ? 0 : CFM_STRIKEOUT; + cf.dwMask = CFM_STRIKEOUT; + CheckDlgButton(hwndDlg, IDC_FONTSTRIKEOUT, !isStrikeout); + } + SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + break; + + case IDC_FONTFACE: + submenu = GetSubMenu(m_pContainer->hMenuContext, 7); + { + CHARFORMAT2 cf; + ZeroMemory(&cf, sizeof(CHARFORMAT2)); + cf.cbSize = sizeof(CHARFORMAT2); + cf.dwMask = CFM_COLOR; + + GetWindowRect(GetDlgItem(hwndDlg, IDC_FONTFACE), &rc); + iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); + if (iSelection == ID_FONT_CLEARALLFORMATTING) { + cf.dwMask = CFM_BOLD | CFM_COLOR | CFM_ITALIC | CFM_UNDERLINE | CFM_STRIKEOUT; + cf.crTextColor = M.GetDword(FONTMODULE, "Font16Col", 0); + SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + break; + } + if (iSelection == ID_FONT_DEFAULTCOLOR) { + cf.crTextColor = M.GetDword(FONTMODULE, "Font16Col", 0); + for (int i=0; i < Utils::rtf_ctable_size; i++) + if (Utils::rtf_ctable[i].clr == cf.crTextColor) + cf.crTextColor = RGB(GetRValue(cf.crTextColor), GetGValue(cf.crTextColor), GetBValue(cf.crTextColor) == 0 ? GetBValue(cf.crTextColor) + 1 : GetBValue(cf.crTextColor) - 1); + + SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + break; + } + for (int i=0; i < RTF_CTABLE_DEFSIZE; i++) + if (Utils::rtf_ctable[i].menuid == iSelection) { + cf.crTextColor = Utils::rtf_ctable[i].clr; + SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + } + break; + + case IDCANCEL: + ShowWindow(hwndContainer, SW_MINIMIZE); + return FALSE; + + case IDC_SAVE: + SendMessage(hwndDlg, WM_CLOSE, 1, 0); + break; + + case IDC_NAME: + if (GetKeyState(VK_SHIFT) & 0x8000) // copy UIN + SendMessage(hwndDlg, DM_UINTOCLIPBOARD, 0, 0); + else + CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)(dat->cache->getActiveContact()), 0); + break; + + case IDC_HISTORY: + CallService(MS_HISTORY_SHOWCONTACTHISTORY, dat->hContact, 0); + break; + + case IDC_SMILEYBTN: + if (dat->doSmileys && PluginConfig.g_SmileyAddAvail) { + MCONTACT hContact = dat->cache->getActiveContact(); + if (CheckValidSmileyPack(dat->cache->getProto(), hContact) != 0) { + SMADD_SHOWSEL3 smaddInfo = {0}; + + if (lParam == 0) + GetWindowRect(GetDlgItem(hwndDlg, IDC_SMILEYBTN), &rc); + else + GetWindowRect((HWND)lParam, &rc); + smaddInfo.cbSize = sizeof(SMADD_SHOWSEL3); + smaddInfo.hwndTarget = GetDlgItem(hwndDlg, IDC_MESSAGE); + smaddInfo.targetMessage = EM_REPLACESEL; + smaddInfo.targetWParam = TRUE; + smaddInfo.Protocolname = const_cast(dat->cache->getProto()); + smaddInfo.Direction = 0; + smaddInfo.xPosition = rc.left; + smaddInfo.yPosition = rc.top + 24; + smaddInfo.hwndParent = hwndContainer; + smaddInfo.hContact = hContact; + CallService(MS_SMILEYADD_SHOWSELECTION, (WPARAM)hwndContainer, (LPARAM)&smaddInfo); + } + } + break; + + case IDC_TIME: + submenu = GetSubMenu(m_pContainer->hMenuContext, 2); + MsgWindowUpdateMenu(dat, submenu, MENU_LOGMENU); + + GetWindowRect(GetDlgItem(hwndDlg, IDC_TIME), &rc); + + iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); + return MsgWindowMenuHandler(dat, iSelection, MENU_LOGMENU); + + case IDC_PROTOMENU: + if (dat->hContact) { + submenu = GetSubMenu(m_pContainer->hMenuContext, 4); + int iOldGlobalSendFormat = PluginConfig.m_SendFormat; + int iLocalFormat = M.GetDword(dat->hContact, "sendformat", 0); + int iNewLocalFormat = iLocalFormat; + + GetWindowRect(GetDlgItem(hwndDlg, IDC_PROTOCOL), &rc); + + CheckMenuItem(submenu, ID_MODE_GLOBAL, MF_BYCOMMAND | (!(dat->dwFlagsEx & MWF_SHOW_SPLITTEROVERRIDE) ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(submenu, ID_MODE_PRIVATE, MF_BYCOMMAND | (dat->dwFlagsEx & MWF_SHOW_SPLITTEROVERRIDE ? MF_CHECKED : MF_UNCHECKED)); + + /* + * formatting menu.. + */ + + CheckMenuItem(submenu, ID_GLOBAL_BBCODE, MF_BYCOMMAND | ((PluginConfig.m_SendFormat) ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(submenu, ID_GLOBAL_OFF, MF_BYCOMMAND | ((PluginConfig.m_SendFormat == SENDFORMAT_NONE) ? MF_CHECKED : MF_UNCHECKED)); + + CheckMenuItem(submenu, ID_THISCONTACT_GLOBALSETTING, MF_BYCOMMAND | ((iLocalFormat == SENDFORMAT_NONE) ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(submenu, ID_THISCONTACT_BBCODE, MF_BYCOMMAND | ((iLocalFormat > 0) ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(submenu, ID_THISCONTACT_OFF, MF_BYCOMMAND | ((iLocalFormat == -1) ? MF_CHECKED : MF_UNCHECKED)); + + iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); + switch (iSelection) { + case ID_MODE_GLOBAL: + dat->dwFlagsEx &= ~(MWF_SHOW_SPLITTEROVERRIDE); + db_set_b(dat->hContact, SRMSGMOD_T, "splitoverride", 0); + LoadSplitter(dat); + AdjustBottomAvatarDisplay(dat); + DM_RecalcPictureSize(dat); + SendMessage(hwndDlg, WM_SIZE, 0, 0); + break; + case ID_MODE_PRIVATE: + dat->dwFlagsEx |= MWF_SHOW_SPLITTEROVERRIDE; + db_set_b(dat->hContact, SRMSGMOD_T, "splitoverride", 1); + LoadSplitter(dat); + AdjustBottomAvatarDisplay(dat); + DM_RecalcPictureSize(dat); + SendMessage(hwndDlg, WM_SIZE, 0, 0); + break; + case ID_GLOBAL_BBCODE: + PluginConfig.m_SendFormat = SENDFORMAT_BBCODE; + break; + case ID_GLOBAL_OFF: + PluginConfig.m_SendFormat = SENDFORMAT_NONE; + break; + case ID_THISCONTACT_GLOBALSETTING: + iNewLocalFormat = 0; + break; + case ID_THISCONTACT_BBCODE: + iNewLocalFormat = SENDFORMAT_BBCODE; + break; + case ID_THISCONTACT_OFF: + iNewLocalFormat = -1; + break; + } + if (iNewLocalFormat == 0) + db_unset(dat->hContact, SRMSGMOD_T, "sendformat"); + else if (iNewLocalFormat != iLocalFormat) + db_set_dw(dat->hContact, SRMSGMOD_T, "sendformat", iNewLocalFormat); + + if (PluginConfig.m_SendFormat != iOldGlobalSendFormat) + db_set_b(0, SRMSGMOD_T, "sendformat", (BYTE)PluginConfig.m_SendFormat); + if (iNewLocalFormat != iLocalFormat || PluginConfig.m_SendFormat != iOldGlobalSendFormat) { + dat->SendFormat = M.GetDword(dat->hContact, "sendformat", PluginConfig.m_SendFormat); + if (dat->SendFormat == -1) // per contact override to disable it.. + dat->SendFormat = 0; + M.BroadcastMessage(DM_CONFIGURETOOLBAR, 0, 1); + } + } + break; + + case IDC_TOGGLETOOLBAR: + if (lParam == 1) + ApplyContainerSetting(m_pContainer, CNT_NOMENUBAR, m_pContainer->dwFlags & CNT_NOMENUBAR ? 0 : 1, true); + else + ApplyContainerSetting(m_pContainer, CNT_HIDETOOLBAR, m_pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1, true); + break; + + case IDC_INFOPANELMENU: + submenu = GetSubMenu(m_pContainer->hMenuContext, 9); + GetWindowRect(GetDlgItem(hwndDlg, IDC_NAME), &rc); + + EnableMenuItem(submenu, ID_FAVORITES_ADDCONTACTTOFAVORITES, !dat->cache->isFavorite() ? MF_ENABLED : MF_GRAYED); + EnableMenuItem(submenu, ID_FAVORITES_REMOVECONTACTFROMFAVORITES, !dat->cache->isFavorite() ? MF_GRAYED : MF_ENABLED); + + iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); + + switch(iSelection) { + case ID_FAVORITES_ADDCONTACTTOFAVORITES: + db_set_b(dat->hContact, SRMSGMOD_T, "isFavorite", 1); + AddContactToFavorites(dat->hContact, dat->cache->getNick(), dat->cache->getProto(), dat->szStatus, dat->wStatus, LoadSkinnedProtoIcon(dat->cache->getProto(), dat->cache->getStatus()), 1, PluginConfig.g_hMenuFavorites); + break; + case ID_FAVORITES_REMOVECONTACTFROMFAVORITES: + db_set_b(dat->hContact, SRMSGMOD_T, "isFavorite", 0); + DeleteMenu(PluginConfig.g_hMenuFavorites, (UINT_PTR)dat->hContact, MF_BYCOMMAND); + break; + } + dat->cache->updateFavorite(); + break; + + case IDC_SENDMENU: + submenu = GetSubMenu(m_pContainer->hMenuContext, 3); + + GetWindowRect(GetDlgItem(hwndDlg, IDOK), &rc); + CheckMenuItem(submenu, ID_SENDMENU_SENDTOMULTIPLEUSERS, MF_BYCOMMAND | (dat->sendMode & SMODE_MULTIPLE ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(submenu, ID_SENDMENU_SENDDEFAULT, MF_BYCOMMAND | (dat->sendMode == 0 ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(submenu, ID_SENDMENU_SENDTOCONTAINER, MF_BYCOMMAND | (dat->sendMode & SMODE_CONTAINER ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(submenu, ID_SENDMENU_FORCEANSISEND, MF_BYCOMMAND | (dat->sendMode & SMODE_FORCEANSI ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(submenu, ID_SENDMENU_SENDLATER, MF_BYCOMMAND | (dat->sendMode & SMODE_SENDLATER ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(submenu, ID_SENDMENU_SENDWITHOUTTIMEOUTS, MF_BYCOMMAND | (dat->sendMode & SMODE_NOACK ? MF_CHECKED : MF_UNCHECKED)); + { + const char *szFinalProto = dat->cache->getActiveProto(); + EnableMenuItem(submenu, ID_SENDMENU_SENDNUDGE, MF_BYCOMMAND | ((ProtoServiceExists(szFinalProto, PS_SEND_NUDGE) && ServiceExists(MS_NUDGE_SEND)) ? MF_ENABLED : MF_GRAYED)); + } + if (lParam) + iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); + else + iSelection = HIWORD(wParam); + + switch (iSelection) { + case ID_SENDMENU_SENDTOMULTIPLEUSERS: + dat->sendMode ^= SMODE_MULTIPLE; + if (dat->sendMode & SMODE_MULTIPLE) + HWND hwndClist = DM_CreateClist(dat); + else { + if (IsWindow(GetDlgItem(hwndDlg, IDC_CLIST))) + DestroyWindow(GetDlgItem(hwndDlg, IDC_CLIST)); + } + break; + case ID_SENDMENU_SENDNUDGE: + SendNudge(dat); + break; + case ID_SENDMENU_SENDDEFAULT: + dat->sendMode = 0; + break; + case ID_SENDMENU_SENDTOCONTAINER: + dat->sendMode ^= SMODE_CONTAINER; + RedrawWindow(hwndDlg, 0, 0, RDW_ERASENOW|RDW_UPDATENOW); + break; + case ID_SENDMENU_FORCEANSISEND: + dat->sendMode ^= SMODE_FORCEANSI; + break; + case ID_SENDMENU_SENDLATER: + if (sendLater->isAvail()) + dat->sendMode ^= SMODE_SENDLATER; + else + CWarning::show(CWarning::WARN_NO_SENDLATER, MB_OK|MB_ICONINFORMATION, TranslateT("Configuration issue|The unattended send feature is disabled. The \\b1 send later\\b0 and \\b1 send to multiple contacts\\b0 features depend on it.\n\nYou must enable it under \\b1Options->Message Sessions->Advanced tweaks\\b0. Changing this option requires a restart.")); + break; + case ID_SENDMENU_SENDWITHOUTTIMEOUTS: + dat->sendMode ^= SMODE_NOACK; + if (dat->sendMode & SMODE_NOACK) + db_set_b(dat->hContact, SRMSGMOD_T, "no_ack", 1); + else + db_unset(dat->hContact, SRMSGMOD_T, "no_ack"); + break; + } + db_set_b(dat->hContact, SRMSGMOD_T, "no_ack", (BYTE)(dat->sendMode & SMODE_NOACK ? 1 : 0)); + db_set_b(dat->hContact, SRMSGMOD_T, "forceansi", (BYTE)(dat->sendMode & SMODE_FORCEANSI ? 1 : 0)); + SetWindowPos(GetDlgItem(hwndDlg, IDC_MESSAGE), 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE); + if (dat->sendMode & SMODE_MULTIPLE || dat->sendMode & SMODE_CONTAINER) { + SetWindowPos(GetDlgItem(hwndDlg, IDC_MESSAGE), 0, 0, 0, 0, 0, SWP_DRAWFRAME|SWP_FRAMECHANGED|SWP_NOZORDER| + SWP_NOMOVE|SWP_NOSIZE|SWP_NOCOPYBITS); + RedrawWindow(hwndDlg, 0, 0, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW|RDW_ALLCHILDREN); + } + else { + if (IsWindow(GetDlgItem(hwndDlg, IDC_CLIST))) + DestroyWindow(GetDlgItem(hwndDlg, IDC_CLIST)); + SetWindowPos(GetDlgItem(hwndDlg, IDC_MESSAGE), 0, 0, 0, 0, 0, SWP_DRAWFRAME|SWP_FRAMECHANGED|SWP_NOZORDER| + SWP_NOMOVE|SWP_NOSIZE|SWP_NOCOPYBITS); + RedrawWindow(hwndDlg, 0, 0, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW|RDW_ALLCHILDREN); + } + SendMessage(hwndContainer, DM_QUERYCLIENTAREA, 0, (LPARAM)&rc); + SendMessage(hwndDlg, WM_SIZE, 0, 0); + DM_ScrollToBottom(dat, 1, 1); + Utils::showDlgControl(hwndDlg, IDC_MULTISPLITTER, (dat->sendMode & SMODE_MULTIPLE) ? SW_SHOW : SW_HIDE); + Utils::showDlgControl(hwndDlg, IDC_CLIST, (dat->sendMode & SMODE_MULTIPLE) ? SW_SHOW : SW_HIDE); + break; + + case IDC_TOGGLESIDEBAR: + SendMessage(m_pContainer->hwnd, WM_COMMAND, IDC_TOGGLESIDEBAR, 0); + break; + + case IDC_PIC: + GetClientRect(hwndDlg, &rc); + + dat->fEditNotesActive = !dat->fEditNotesActive; + if (dat->fEditNotesActive) { + int iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE)); + if (iLen != 0) { + SendMessage(hwndDlg, DM_ACTIVATETOOLTIP, IDC_MESSAGE, (LPARAM)TranslateT("You cannot edit user notes when there are unsent messages")); + dat->fEditNotesActive = false; + break; + } + + if (!dat->bIsAutosizingInput) { + dat->iSplitterSaved = dat->splitterY; + dat->splitterY = rc.bottom / 2; + SendMessage(hwndDlg, WM_SIZE, 1, 1); + } + + DBVARIANT dbv = {0}; + + if (0 == db_get_ts(dat->hContact, "UserInfo", "MyNotes", &dbv)) { + SetDlgItemText(hwndDlg, IDC_MESSAGE, dbv.ptszVal); + mir_free(dbv.ptszVal); + } + } + else { + int iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE)); + + TCHAR *buf = (TCHAR*)mir_alloc((iLen + 2) * sizeof(TCHAR)); + GetDlgItemText(hwndDlg, IDC_MESSAGE, buf, iLen + 1); + db_set_ts(dat->hContact, "UserInfo", "MyNotes", buf); + SetDlgItemText(hwndDlg, IDC_MESSAGE, _T("")); + + if (!dat->bIsAutosizingInput) { + dat->splitterY = dat->iSplitterSaved; + SendMessage(hwndDlg, WM_SIZE, 0, 0); + DM_ScrollToBottom(dat, 0, 1); + } + } + SetWindowPos(GetDlgItem(hwndDlg, IDC_MESSAGE), 0, 0, 0, 0, 0, SWP_DRAWFRAME|SWP_FRAMECHANGED|SWP_NOZORDER| + SWP_NOMOVE|SWP_NOSIZE|SWP_NOCOPYBITS); + RedrawWindow(hwndDlg, 0, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME|RDW_UPDATENOW|RDW_ALLCHILDREN); + + if (dat->fEditNotesActive) + CWarning::show(CWarning::WARN_EDITUSERNOTES, MB_OK|MB_ICONINFORMATION); + break; + + case IDM_CLEAR: + ClearLog(dat); + break; + + case IDC_PROTOCOL: + submenu = (HMENU) CallService(MS_CLIST_MENUBUILDCONTACT, dat->hContact, 0); + if (lParam == 0) + GetWindowRect(GetDlgItem(hwndDlg, IDC_PROTOCOL), &rc); + else + GetWindowRect((HWND)lParam, &rc); + + iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); + if (iSelection) + CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(iSelection), MPCF_CONTACTMENU), (LPARAM)dat->hContact); + + DestroyMenu(submenu); + break; + + // error control + case IDC_CANCELSEND: + SendMessage(hwndDlg, DM_ERRORDECIDED, MSGERROR_CANCEL, 0); + break; + + case IDC_RETRY: + SendMessage(hwndDlg, DM_ERRORDECIDED, MSGERROR_RETRY, 0); + break; + + case IDC_MSGSENDLATER: + SendMessage(hwndDlg, DM_ERRORDECIDED, MSGERROR_SENDLATER, 0); + break; + + case IDC_SELFTYPING: + if (dat->hContact) { + int iCurrentTypingMode = db_get_b(dat->hContact, SRMSGMOD, SRMSGSET_TYPING, M.GetByte(SRMSGMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW)); + + if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON && iCurrentTypingMode) { + DM_NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF); + dat->nTypeMode = PROTOTYPE_SELFTYPING_OFF; + } + db_set_b(dat->hContact, SRMSGMOD, SRMSGSET_TYPING, (BYTE)!iCurrentTypingMode); + } + break; + + default: + return 0; + } + return 1; +} + +static INT_PTR CALLBACK DlgProcAbout(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + COLORREF url_visited = RGB(128, 0, 128); + COLORREF url_unvisited = RGB(0, 0, 255); + + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + { + WORD v[4]; + CallService(MS_SYSTEM_GETFILEVERSION, 0, (LPARAM)&v); + + TCHAR tStr[80]; + mir_sntprintf(tStr, SIZEOF(tStr), _T("TabSRMM\n%s %d.%d.%d.%d [build %d]"), + TranslateT("Version"), __MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM, v[3]); + SetDlgItemText(hwndDlg, IDC_HEADERBAR, tStr); + } + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_MESSAGE)); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIconBig(SKINICON_EVENT_MESSAGE)); + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + case IDCANCEL: + DestroyWindow(hwndDlg); + return TRUE; + case IDC_SUPPORT: + CallService(MS_UTILS_OPENURL, 1, (LPARAM)"http://miranda.or.at/"); + break; + } + break; + + case WM_CTLCOLOREDIT: + case WM_CTLCOLORSTATIC: + SetTextColor((HDC)wParam, RGB(60, 60, 150)); + SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW)); + return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); + } + return FALSE; +} + +LRESULT TSAPI DM_ContainerCmdHandler(TContainerData *pContainer, UINT cmd, WPARAM wParam, LPARAM lParam) +{ + if (!pContainer) + return 0; + + HWND hwndDlg = pContainer->hwnd; + TWindowData *dat = (TWindowData*)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA); + + switch(cmd) { + case IDC_CLOSE: + SendMessage(hwndDlg, WM_SYSCOMMAND, SC_CLOSE, 0); + break; + case IDC_MINIMIZE: + PostMessage(hwndDlg, WM_SYSCOMMAND, SC_MINIMIZE, 0); + break; + case IDC_MAXIMIZE: + SendMessage(hwndDlg, WM_SYSCOMMAND, IsZoomed(hwndDlg) ? SC_RESTORE : SC_MAXIMIZE, 0); + break; + case IDOK: + SendMessage(pContainer->hwndActive, WM_COMMAND, wParam, lParam); // pass the IDOK command to the active child - fixes the "enter not working + break; + case ID_FILE_SAVEMESSAGELOGAS: + SendMessage(pContainer->hwndActive, DM_SAVEMESSAGELOG, 0, 0); + break; + case ID_FILE_CLOSEMESSAGESESSION: + PostMessage(pContainer->hwndActive, WM_CLOSE, 0, 1); + break; + case ID_FILE_CLOSE: + PostMessage(hwndDlg, WM_CLOSE, 0, 1); + break; + case ID_VIEW_SHOWSTATUSBAR: + ApplyContainerSetting(pContainer, CNT_NOSTATUSBAR, pContainer->dwFlags & CNT_NOSTATUSBAR ? 0 : 1, true); + break; + case ID_VIEW_VERTICALMAXIMIZE: + ApplyContainerSetting(pContainer, CNT_VERTICALMAX, pContainer->dwFlags & CNT_VERTICALMAX ? 0 : 1, false); + break; + case ID_VIEW_BOTTOMTOOLBAR: + ApplyContainerSetting(pContainer, CNT_BOTTOMTOOLBAR, pContainer->dwFlags & CNT_BOTTOMTOOLBAR ? 0 : 1, false); + M.BroadcastMessage(DM_CONFIGURETOOLBAR, 0, 1); + return 0; + case ID_VIEW_SHOWTOOLBAR: + ApplyContainerSetting(pContainer, CNT_HIDETOOLBAR, pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1, false); + M.BroadcastMessage(DM_CONFIGURETOOLBAR, 0, 1); + return 0; + case ID_VIEW_SHOWMENUBAR: + ApplyContainerSetting(pContainer, CNT_NOMENUBAR, pContainer->dwFlags & CNT_NOMENUBAR ? 0 : 1, true); + break; + case ID_VIEW_SHOWTITLEBAR: + ApplyContainerSetting(pContainer, CNT_NOTITLE, pContainer->dwFlags & CNT_NOTITLE ? 0 : 1, true); + break; + case ID_VIEW_TABSATBOTTOM: + ApplyContainerSetting(pContainer, CNT_TABSBOTTOM, pContainer->dwFlags & CNT_TABSBOTTOM ? 0 : 1, false); + break; + case ID_VIEW_SHOWMULTISENDCONTACTLIST: + SendMessage(pContainer->hwndActive, WM_COMMAND, MAKEWPARAM(IDC_SENDMENU, ID_SENDMENU_SENDTOMULTIPLEUSERS), 0); + break; + case ID_VIEW_STAYONTOP: + SendMessage(hwndDlg, WM_SYSCOMMAND, IDM_STAYONTOP, 0); + break; + case ID_CONTAINER_CONTAINEROPTIONS: + SendMessage(hwndDlg, WM_SYSCOMMAND, IDM_MOREOPTIONS, 0); + break; + case ID_EVENTPOPUPS_DISABLEALLEVENTPOPUPS: + ApplyContainerSetting(pContainer, (CNT_DONTREPORT | CNT_DONTREPORTUNFOCUSED | CNT_DONTREPORTFOCUSED | CNT_ALWAYSREPORTINACTIVE), 0, false); + return 0; + case ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISMINIMIZED: + ApplyContainerSetting(pContainer, CNT_DONTREPORT, pContainer->dwFlags & CNT_DONTREPORT ? 0 : 1, false); + return 0; + case ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISUNFOCUSED: + ApplyContainerSetting(pContainer, CNT_DONTREPORTUNFOCUSED, pContainer->dwFlags & CNT_DONTREPORTUNFOCUSED ? 0 : 1, false); + return 0; + case ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISFOCUSED: + ApplyContainerSetting(pContainer, CNT_DONTREPORTFOCUSED, pContainer->dwFlags & CNT_DONTREPORTFOCUSED ? 0 : 1, false); + return 0; + case ID_EVENTPOPUPS_SHOWPOPUPSFORALLINACTIVESESSIONS: + ApplyContainerSetting(pContainer, CNT_ALWAYSREPORTINACTIVE, pContainer->dwFlags & CNT_ALWAYSREPORTINACTIVE ? 0 : 1, false); + return 0; + case ID_WINDOWFLASHING_DISABLEFLASHING: + ApplyContainerSetting(pContainer, CNT_NOFLASH, 1, false); + ApplyContainerSetting(pContainer, CNT_FLASHALWAYS, 0, false); + return 0; + case ID_WINDOWFLASHING_FLASHUNTILFOCUSED: + ApplyContainerSetting(pContainer, CNT_NOFLASH, 0, false); + ApplyContainerSetting(pContainer, CNT_FLASHALWAYS, 1, false); + return 0; + case ID_WINDOWFLASHING_USEDEFAULTVALUES: + ApplyContainerSetting(pContainer, (CNT_NOFLASH | CNT_FLASHALWAYS), 0, false); + return 0; + case ID_OPTIONS_SAVECURRENTWINDOWPOSITIONASDEFAULT: + { + WINDOWPLACEMENT wp = {0}; + wp.length = sizeof(wp); + if (GetWindowPlacement(hwndDlg, &wp)) { + db_set_dw(0, SRMSGMOD_T, "splitx", wp.rcNormalPosition.left); + db_set_dw(0, SRMSGMOD_T, "splity", wp.rcNormalPosition.top); + db_set_dw(0, SRMSGMOD_T, "splitwidth", wp.rcNormalPosition.right - wp.rcNormalPosition.left); + db_set_dw(0, SRMSGMOD_T, "splitheight", wp.rcNormalPosition.bottom - wp.rcNormalPosition.top); + } + } + return 0; + + case ID_VIEW_INFOPANEL: + if (dat) { + RECT rc; + POINT pt; + GetWindowRect(pContainer->hwndActive, &rc); + pt.x = rc.left + 10; + pt.y = rc.top + dat->Panel->getHeight() - 10; + dat->Panel->invokeConfigDialog(pt); + } + return 0; + + /* + * commands from the message log popup will be routed to the + * message log menu handler + */ + case ID_MESSAGELOGSETTINGS_FORTHISCONTACT: + case ID_MESSAGELOGSETTINGS_GLOBAL: + if (dat) { + MsgWindowMenuHandler(dat, (int)LOWORD(wParam), MENU_LOGMENU); + return 1; + } + break; + + case ID_HELP_ABOUTTABSRMM: + CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_ABOUT), 0, DlgProcAbout, 0); + break; + + default: + return 0; // not handled + } + return 1; // handled +} + +/** + * initialize rich edit control (log and edit control) for both MUC and + * standard IM session windows. + */ +void TSAPI DM_InitRichEdit(TWindowData *dat) +{ + char *szStreamOut = NULL; + bool fIsChat = ((dat->bType == SESSIONTYPE_CHAT) ? true : false); + HWND hwndLog = GetDlgItem(dat->hwnd, !fIsChat ? IDC_LOG : IDC_CHAT_LOG); + HWND hwndEdit= GetDlgItem(dat->hwnd, !fIsChat ? IDC_MESSAGE : IDC_CHAT_MESSAGE); + HWND hwndDlg = dat->hwnd; + + dat->inputbg = fIsChat ? M.GetDword(FONTMODULE, "inputbg", SRMSGDEFSET_BKGCOLOUR) : dat->pContainer->theme.inputbg; + COLORREF colour = fIsChat ? g_Settings.crLogBackground : dat->pContainer->theme.bg; + COLORREF inputcharcolor; + + if (!fIsChat && GetWindowTextLengthA(hwndEdit) > 0) + szStreamOut = Message_GetFromStream(hwndEdit, dat, (CP_UTF8 << 16) | (SF_RTFNOOBJS | SFF_PLAINRTF | SF_USECODEPAGE)); + + SendMessage(hwndLog, EM_SETBKGNDCOLOR, 0, colour); + SendMessage(hwndEdit, EM_SETBKGNDCOLOR, 0, dat->inputbg); + + CHARFORMAT2A cf2; + ZeroMemory(&cf2, sizeof(CHARFORMAT2A)); + cf2.cbSize = sizeof(cf2); + + if (fIsChat) { + LOGFONTA lf; + LoadLogfont(MSGFONTID_MESSAGEAREA, &lf, &inputcharcolor, FONTMODULE); + + cf2.dwMask = CFM_COLOR | CFM_FACE | CFM_CHARSET | CFM_SIZE | CFM_WEIGHT | CFM_ITALIC | CFM_BACKCOLOR; + cf2.crTextColor = inputcharcolor; + cf2.bCharSet = lf.lfCharSet; + cf2.crBackColor = dat->inputbg; + strncpy(cf2.szFaceName, lf.lfFaceName, LF_FACESIZE); + cf2.dwEffects = 0; + cf2.wWeight = (WORD)lf.lfWeight; + cf2.bPitchAndFamily = lf.lfPitchAndFamily; + cf2.yHeight = abs(lf.lfHeight) * 15; + SetWindowText(hwndEdit, _T("")); + SendMessage(hwndEdit, EM_SETCHARFORMAT, 0, (LPARAM)&cf2); + } + else { + LOGFONTA lf = dat->pContainer->theme.logFonts[MSGFONTID_MESSAGEAREA]; + inputcharcolor = dat->pContainer->theme.fontColors[MSGFONTID_MESSAGEAREA]; + + for (int i=0; i < Utils::rtf_ctable_size; i++) + if (Utils::rtf_ctable[i].clr == inputcharcolor) + inputcharcolor = RGB(GetRValue(inputcharcolor), GetGValue(inputcharcolor), GetBValue(inputcharcolor) == 0 ? GetBValue(inputcharcolor) + 1 : GetBValue(inputcharcolor) - 1); + + cf2.dwMask = CFM_COLOR | CFM_FACE | CFM_CHARSET | CFM_SIZE | CFM_WEIGHT | CFM_BOLD | CFM_ITALIC; + cf2.crTextColor = inputcharcolor; + cf2.bCharSet = lf.lfCharSet; + strncpy(cf2.szFaceName, lf.lfFaceName, LF_FACESIZE); + cf2.dwEffects = ((lf.lfWeight >= FW_BOLD) ? CFE_BOLD : 0) | (lf.lfItalic ? CFE_ITALIC : 0)|(lf.lfUnderline ? CFE_UNDERLINE : 0)|(lf.lfStrikeOut ? CFE_STRIKEOUT : 0); + cf2.wWeight = (WORD)lf.lfWeight; + cf2.bPitchAndFamily = lf.lfPitchAndFamily; + cf2.yHeight = abs(lf.lfHeight) * 15; + SendMessageA(hwndEdit, EM_SETCHARFORMAT, 0, (LPARAM)&cf2); + } + + /* + * setup the rich edit control(s) + * LOG is always set to RTL, because this is needed for proper bidirectional operation later. + * The real text direction is then enforced by the streaming code which adds appropiate paragraph + * and textflow formatting commands to the + */ + + PARAFORMAT2 pf2; + ZeroMemory(&pf2, sizeof(PARAFORMAT2)); + pf2.cbSize = sizeof(pf2); + pf2.wEffects = PFE_RTLPARA; + pf2.dwMask = PFM_RTLPARA; + if (Utils::FindRTLLocale(dat)) + SendMessage(hwndEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf2); + if (!(dat->dwFlags & MWF_LOG_RTL)) { + pf2.wEffects = 0; + SendMessage(hwndEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf2); + } + SendMessage(hwndEdit, EM_SETLANGOPTIONS, 0, (LPARAM)SendMessage(hwndEdit, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD); + pf2.wEffects = PFE_RTLPARA; + pf2.dwMask |= PFM_OFFSET; + if (dat->dwFlags & MWF_INITMODE) { + pf2.dwMask |= (PFM_RIGHTINDENT | PFM_OFFSETINDENT); + pf2.dxStartIndent = 30; + pf2.dxRightIndent = 30; + } + pf2.dxOffset = dat->pContainer->theme.left_indent + 30; + if (!fIsChat) { + SetWindowText(hwndLog, _T("")); + SendMessage(hwndLog, EM_SETPARAFORMAT, 0, (LPARAM)&pf2); + SendMessage(hwndLog, EM_SETLANGOPTIONS, 0, (LPARAM)SendDlgItemMessage(hwndDlg, IDC_LOG, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD); + } + + /* + * set the scrollbars etc to RTL/LTR (only for manual RTL mode) + */ + + if (!fIsChat) { + if (dat->dwFlags & MWF_LOG_RTL) { + SetWindowLongPtr(hwndEdit, GWL_EXSTYLE, GetWindowLongPtr(hwndEdit, GWL_EXSTYLE) | WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR); + SetWindowLongPtr(hwndLog, GWL_EXSTYLE, GetWindowLongPtr(hwndLog, GWL_EXSTYLE) | WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR); + } + else { + SetWindowLongPtr(hwndEdit, GWL_EXSTYLE, GetWindowLongPtr(hwndEdit, GWL_EXSTYLE) &~(WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR)); + SetWindowLongPtr(hwndLog, GWL_EXSTYLE, GetWindowLongPtr(hwndLog, GWL_EXSTYLE) &~(WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR)); + } + SetWindowText(hwndEdit, _T("")); + } + if (szStreamOut != NULL) { + SETTEXTEX stx = {ST_DEFAULT, CP_UTF8}; + SendMessage(hwndEdit, EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)szStreamOut); + mir_free(szStreamOut); + } +} + +/* +* set the states of defined database action buttons (only if button is a toggle) +*/ + +void TSAPI DM_SetDBButtonStates(HWND hwndChild, TWindowData *dat) +{ + ButtonItem *buttonItem = dat->pContainer->buttonItems; + MCONTACT hContact = dat->hContact, hFinalContact = 0; + char *szModule, *szSetting; + HWND hwndContainer = dat->pContainer->hwnd; + + while (buttonItem) { + BOOL result = FALSE; + HWND hWnd = GetDlgItem(hwndContainer, buttonItem->uId); + + if (buttonItem->pfnCallback) + buttonItem->pfnCallback(buttonItem, hwndChild, dat, hWnd); + + if (!(buttonItem->dwFlags & BUTTON_ISTOGGLE && buttonItem->dwFlags & BUTTON_ISDBACTION)) { + buttonItem = buttonItem->nextItem; + continue; + } + szModule = buttonItem->szModule; + szSetting = buttonItem->szSetting; + if (buttonItem->dwFlags & BUTTON_DBACTIONONCONTACT || buttonItem->dwFlags & BUTTON_ISCONTACTDBACTION) { + if (hContact == 0) { + SendMessage(hWnd, BM_SETCHECK, BST_UNCHECKED, 0); + buttonItem = buttonItem->nextItem; + continue; + } + if (buttonItem->dwFlags & BUTTON_ISCONTACTDBACTION) + szModule = GetContactProto(hContact); + hFinalContact = hContact; + } else + hFinalContact = 0; + + if (buttonItem->type == DBVT_ASCIIZ) { + DBVARIANT dbv = {0}; + + if (!db_get_s(hFinalContact, szModule, szSetting, &dbv)) { + result = !strcmp((char *)buttonItem->bValuePush, dbv.pszVal); + db_free(&dbv); + } + } else { + switch (buttonItem->type) { + case DBVT_BYTE: { + BYTE val = db_get_b(hFinalContact, szModule, szSetting, 0); + result = (val == buttonItem->bValuePush[0]); + break; + } + case DBVT_WORD: { + WORD val = db_get_w(hFinalContact, szModule, szSetting, 0); + result = (val == *((WORD *) & buttonItem->bValuePush)); + break; + } + case DBVT_DWORD: { + DWORD val = db_get_dw(hFinalContact, szModule, szSetting, 0); + result = (val == *((DWORD *) & buttonItem->bValuePush)); + break; + } + } + } + SendMessage(hWnd, BM_SETCHECK, (WPARAM)result, 0); + buttonItem = buttonItem->nextItem; + } +} + +void TSAPI DM_ScrollToBottom(TWindowData *dat, WPARAM wParam, LPARAM lParam) +{ + if (dat == NULL) + return; + + if (dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED) + return; + + if ( IsIconic(dat->pContainer->hwnd)) + dat->dwFlags |= MWF_DEFERREDSCROLL; + + if (dat->hwndIEView) { + PostMessage(dat->hwnd, DM_SCROLLIEVIEW, 0, 0); + return; + } + if (dat->hwndHPP) { + SendMessage(dat->hwnd, DM_SCROLLIEVIEW, 0, 0); + return; + } + + HWND hwnd = GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_LOG : IDC_CHAT_LOG); + if (lParam) + SendMessage(hwnd, WM_SIZE, 0, 0); + + if (wParam == 1 && lParam == 1) { + RECT rc; + GetClientRect(hwnd, &rc); + int len = GetWindowTextLengthA(hwnd); + SendMessage(hwnd, EM_SETSEL, len - 1, len - 1); + } + + if (wParam) + SendMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), 0); + else + PostMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), 0); + + if (lParam) + InvalidateRect(hwnd, NULL, FALSE); +} + +static void LoadKLThread(LPVOID _param) +{ + DBVARIANT dbv; + if (!db_get_ts((MCONTACT)_param, SRMSGMOD_T, "locale", &dbv)) { + HKL hkl = LoadKeyboardLayout(dbv.ptszVal, 0); + PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_SETLOCALE, (WPARAM)_param, (LPARAM)hkl); + db_free(&dbv); + } +} + +void TSAPI DM_LoadLocale(TWindowData *dat) +{ + if (dat == NULL || !PluginConfig.m_AutoLocaleSupport) + return; + + if (dat->dwFlags & MWF_WASBACKGROUNDCREATE) + return; + + DBVARIANT dbv; + if ( !db_get_ts(dat->hContact, SRMSGMOD_T, "locale", &dbv)) + db_free(&dbv); + else { + TCHAR szKLName[KL_NAMELENGTH+1]; + if (!PluginConfig.m_dontUseDefaultKbd) { + TCHAR szBuf[20]; + GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_ILANGUAGE, szBuf, 20); + mir_sntprintf(szKLName, KL_NAMELENGTH, _T("0000%s"), szBuf); + db_set_ts(dat->hContact, SRMSGMOD_T, "locale", szKLName); + } + else { + GetKeyboardLayoutName(szKLName); + db_set_ts(dat->hContact, SRMSGMOD_T, "locale", szKLName); + } + } + + mir_forkthread(LoadKLThread, (void*)dat->hContact); +} + +LRESULT TSAPI DM_RecalcPictureSize(TWindowData *dat) +{ + if (dat) { + HBITMAP hbm = ((dat->Panel->isActive()) && dat->pContainer->avatarMode != 3) ? dat->hOwnPic : (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown); + if (hbm) { + BITMAP bminfo; + GetObject(hbm, sizeof(bminfo), &bminfo); + CalcDynamicAvatarSize(dat, &bminfo); + SendMessage(dat->hwnd, WM_SIZE, 0, 0); + } + else dat->pic.cy = dat->pic.cx = 60; + } + return 0; +} + +void TSAPI DM_UpdateLastMessage(const TWindowData *dat) +{ + if (dat == NULL) + return; + + if (dat->pContainer->hwndStatus == 0 || dat->pContainer->hwndActive != dat->hwnd) + return; + + TCHAR szBuf[100]; + if (dat->showTyping) { + SendMessage(dat->pContainer->hwndStatus, SB_SETICON, 0, (LPARAM)PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]); + mir_sntprintf(szBuf, SIZEOF(szBuf), TranslateT("%s is typing a message..."), dat->cache->getNick()); + } + else { + SendMessage(dat->pContainer->hwndStatus, SB_SETICON, 0, 0); + + if (dat->pContainer->dwFlags & CNT_UINSTATUSBAR) + mir_sntprintf(szBuf, SIZEOF(szBuf), _T("UID: %s"), dat->cache->getUIN()); + else if (dat->lastMessage) { + TCHAR date[64], time[64]; + tmi.printTimeStamp(NULL, dat->lastMessage, _T("d"), date, SIZEOF(date), 0); + if (dat->pContainer->dwFlags & CNT_UINSTATUSBAR && lstrlen(date) > 6) + date[lstrlen(date) - 5] = 0; + tmi.printTimeStamp(NULL, dat->lastMessage, _T("t"), time, SIZEOF(time), 0); + mir_sntprintf(szBuf, SIZEOF(szBuf), TranslateT("Last received: %s at %s"), date, time); + } + else szBuf[0] = 0; + } + + SendMessage(dat->pContainer->hwndStatus, SB_SETTEXT, 0, (LPARAM)szBuf); +} + +/* +* save current keyboard layout for the given contact +*/ + +void TSAPI DM_SaveLocale(TWindowData *dat, WPARAM wParam, LPARAM lParam) +{ + if (!dat) + return; + + if (PluginConfig.m_AutoLocaleSupport && dat->hContact && dat->pContainer->hwndActive == dat->hwnd) { + TCHAR szKLName[KL_NAMELENGTH + 1]; + if ((HKL)lParam != dat->hkl) { + dat->hkl = (HKL)lParam; + ActivateKeyboardLayout(dat->hkl, 0); + GetKeyboardLayoutName(szKLName); + db_set_ts(dat->hContact, SRMSGMOD_T, "locale", szKLName); + GetLocaleID(dat, szKLName); + UpdateReadChars(dat); + } + } +} + +/* +* generic handler for the WM_COPY message in message log/chat history richedit control(s). +* it filters out the invisible event boundary markers from the text copied to the clipboard. +*/ + +LRESULT TSAPI DM_WMCopyHandler(HWND hwnd, WNDPROC oldWndProc, UINT msg, WPARAM wParam, LPARAM lParam) +{ + LRESULT result = mir_callNextSubclass(hwnd, oldWndProc, msg, wParam, lParam); + + if (OpenClipboard(hwnd)) { + HANDLE hClip = GetClipboardData(CF_UNICODETEXT); + if (hClip) { + HGLOBAL hgbl; + TCHAR *tszLocked; + TCHAR *tszText = (TCHAR*)mir_alloc((lstrlen((TCHAR*)hClip) + 2) * sizeof(TCHAR)); + + lstrcpy(tszText, (TCHAR*)hClip); + Utils::FilterEventMarkers(tszText); + EmptyClipboard(); + + hgbl = GlobalAlloc(GMEM_MOVEABLE, (lstrlen(tszText) + 1) * sizeof(TCHAR)); + tszLocked = (TCHAR*)GlobalLock(hgbl); + lstrcpy(tszLocked, tszText); + GlobalUnlock(hgbl); + SetClipboardData(CF_UNICODETEXT, hgbl); + if (tszText) + mir_free(tszText); + } + CloseClipboard(); + } + return result; +} + +/* +* create embedded contact list control +*/ + +HWND TSAPI DM_CreateClist(TWindowData *dat) +{ + if (!sendLater->isAvail()) { + CWarning::show(CWarning::WARN_NO_SENDLATER, MB_OK|MB_ICONINFORMATION, TranslateT("Configuration issue|The unattended send feature is disabled. The \\b1 send later\\b0 and \\b1 send to multiple contacts\\b0 features depend on it.\n\nYou must enable it under \\b1Options->Message Sessions->Advanced tweaks\\b0. Changing this option requires a restart.")); + dat->sendMode &= ~SMODE_MULTIPLE; + return 0; + } + + HWND hwndClist = CreateWindowExA(0, "CListControl", "", WS_TABSTOP | WS_VISIBLE | WS_CHILD | 0x248, + 184, 0, 30, 30, dat->hwnd, (HMENU)IDC_CLIST, g_hInst, NULL); + SendMessage(hwndClist, WM_TIMER, 14, 0); + HANDLE hItem = (HANDLE)SendMessage(hwndClist, CLM_FINDCONTACT, dat->hContact, 0); + + SetWindowLongPtr(hwndClist, GWL_EXSTYLE, GetWindowLongPtr(hwndClist, GWL_EXSTYLE) & ~CLS_EX_TRACKSELECT); + SetWindowLongPtr(hwndClist, GWL_EXSTYLE, GetWindowLongPtr(hwndClist, GWL_EXSTYLE) | (CLS_EX_NOSMOOTHSCROLLING | CLS_EX_NOTRANSLUCENTSEL)); + + if (!PluginConfig.m_AllowOfflineMultisend) + SetWindowLongPtr(hwndClist, GWL_STYLE, GetWindowLongPtr(hwndClist, GWL_STYLE) | CLS_HIDEOFFLINE); + + if (hItem) + SendMessage(hwndClist, CLM_SETCHECKMARK, (WPARAM)hItem, 1); + + if (CallService(MS_CLUI_GETCAPS, 0, 0) & CLUIF_DISABLEGROUPS && !M.GetByte("CList", "UseGroups", SETTING_USEGROUPS_DEFAULT)) + SendMessage(hwndClist, CLM_SETUSEGROUPS, FALSE, 0); + else + SendMessage(hwndClist, CLM_SETUSEGROUPS, TRUE, 0); + if (CallService(MS_CLUI_GETCAPS, 0, 0) & CLUIF_HIDEEMPTYGROUPS && M.GetByte("CList", "HideEmptyGroups", SETTING_USEGROUPS_DEFAULT)) + SendMessage(hwndClist, CLM_SETHIDEEMPTYGROUPS, TRUE, 0); + else + SendMessage(hwndClist, CLM_SETHIDEEMPTYGROUPS, FALSE, 0); + SendMessage(hwndClist, CLM_FIRST + 106, 0, 1); + SendMessage(hwndClist, CLM_AUTOREBUILD, 0, 0); + if (hwndClist) + RedrawWindow(hwndClist, 0, 0, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW); + return hwndClist; +} + +LRESULT TSAPI DM_MouseWheelHandler(HWND hwnd, HWND hwndParent, TWindowData *mwdat, WPARAM wParam, LPARAM lParam) +{ + RECT rc, rc1; + UINT uID = mwdat->bType == SESSIONTYPE_IM ? IDC_LOG : IDC_CHAT_LOG; + UINT uIDMsg = mwdat->bType == SESSIONTYPE_IM ? IDC_MESSAGE : IDC_CHAT_MESSAGE; + + POINT pt; + GetCursorPos(&pt); + GetWindowRect(hwnd, &rc); + if (PtInRect(&rc, pt)) + return 1; + + if (mwdat->pContainer->dwFlags & CNT_SIDEBAR) { + GetWindowRect(GetDlgItem(mwdat->pContainer->hwnd, IDC_SIDEBARUP), &rc); + GetWindowRect(GetDlgItem(mwdat->pContainer->hwnd, IDC_SIDEBARDOWN), &rc1); + rc.bottom = rc1.bottom; + if (PtInRect(&rc, pt)) { + short amount = (short)(HIWORD(wParam)); + SendMessage(mwdat->pContainer->hwnd, WM_COMMAND, MAKELONG(amount > 0 ? IDC_SIDEBARUP : IDC_SIDEBARDOWN, 0), (LPARAM)uIDMsg); + return 0; + } + } + if (mwdat->bType == SESSIONTYPE_CHAT) { // scroll nick list by just hovering it + RECT rcNicklist; + GetWindowRect(GetDlgItem(mwdat->hwnd, IDC_LIST), &rcNicklist); + if (PtInRect(&rcNicklist, pt)) { + SendMessage(GetDlgItem(mwdat->hwnd, IDC_LIST), WM_MOUSEWHEEL, wParam, lParam); + return 0; + } + } + if (mwdat->hwndIEView) + GetWindowRect(mwdat->hwndIEView, &rc); + else if (mwdat->hwndHPP) + GetWindowRect(mwdat->hwndHPP, &rc); + else + GetWindowRect(GetDlgItem(hwndParent, uID), &rc); + if (PtInRect(&rc, pt)) { + HWND hwnd = (mwdat->hwndIEView || mwdat->hwndHPP) ? mwdat->hwndIWebBrowserControl : GetDlgItem(hwndParent, uID); + short wDirection = (short)HIWORD(wParam); + + if (hwnd == 0) + hwnd = WindowFromPoint(pt); + + if (LOWORD(wParam) & MK_SHIFT || M.GetByte("fastscroll", 0)) { + if (wDirection < 0) + SendMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_PAGEDOWN, 0), 0); + else if (wDirection > 0) + SendMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_PAGEUP, 0), 0); + } + else SendMessage(hwnd, WM_MOUSEWHEEL, wParam, lParam); + return 0; + } + + HWND hwndTab = GetDlgItem(mwdat->pContainer->hwnd, IDC_MSGTABS); + TCHITTESTINFO hti; + GetCursorPos(&hti.pt); + ScreenToClient(hwndTab, &hti.pt); + hti.flags = 0; + if (TabCtrl_HitTest(hwndTab, &hti) != -1) { + SendMessage(hwndTab, WM_MOUSEWHEEL, wParam, -1); + return 0; + } + return 1; +} + +void TSAPI DM_FreeTheme(TWindowData *dat) +{ + if (dat) { + if (dat->hTheme) { + CloseThemeData(dat->hTheme); + dat->hTheme = 0; + } + if (dat->hThemeIP) { + CloseThemeData(dat->hThemeIP); + dat->hThemeIP = 0; + } + if (dat->hThemeToolbar) { + CloseThemeData(dat->hThemeToolbar); + dat->hThemeToolbar = 0; + } + } +} + +LRESULT TSAPI DM_ThemeChanged(TWindowData *dat) +{ + CSkinItem *item_log = &SkinItems[ID_EXTBKHISTORY]; + CSkinItem *item_msg = &SkinItems[ID_EXTBKINPUTAREA]; + + HWND hwnd = dat->hwnd; + + dat->hTheme = OpenThemeData(hwnd, L"EDIT"); + + if (dat->bType == SESSIONTYPE_IM) { + if (dat->hTheme != 0 || (CSkin::m_skinEnabled && !item_log->IGNORED)) + SetWindowLongPtr(GetDlgItem(hwnd, IDC_LOG), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwnd, IDC_LOG), GWL_EXSTYLE) & ~WS_EX_STATICEDGE); + if (dat->hTheme != 0 || (CSkin::m_skinEnabled && !item_msg->IGNORED)) + SetWindowLongPtr(GetDlgItem(hwnd, IDC_MESSAGE), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwnd, IDC_MESSAGE), GWL_EXSTYLE) & ~WS_EX_STATICEDGE); + } + else { + if (dat->hTheme != 0 || (CSkin::m_skinEnabled && !item_log->IGNORED)) { + SetWindowLongPtr(GetDlgItem(hwnd, IDC_CHAT_LOG), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwnd, IDC_CHAT_LOG), GWL_EXSTYLE) & ~WS_EX_STATICEDGE); + SetWindowLongPtr(GetDlgItem(hwnd, IDC_LIST), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwnd, IDC_LIST), GWL_EXSTYLE) & ~(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE)); + } + if (dat->hTheme != 0 || (CSkin::m_skinEnabled && !item_msg->IGNORED)) + SetWindowLongPtr(GetDlgItem(hwnd, IDC_CHAT_MESSAGE), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwnd, IDC_CHAT_MESSAGE), GWL_EXSTYLE) & ~WS_EX_STATICEDGE); + } + dat->hThemeIP = M.isAero() ? OpenThemeData(hwnd, L"ButtonStyle") : 0; + dat->hThemeToolbar = (M.isAero() || (!CSkin::m_skinEnabled && M.isVSThemed())) ? OpenThemeData(hwnd, L"REBAR") : 0; + + return 0; +} + +/** + * send out message typing notifications (MTN) when the + * user is typing/editing text in the message input area. + */ +void TSAPI DM_NotifyTyping(TWindowData *dat, int mode) +{ + if (!dat || !dat->hContact) + return; + + DeletePopupsForContact(dat->hContact, PU_REMOVE_ON_TYPE); + + const char *szProto = 0; + MCONTACT hContact = 0; + if (dat->bIsMeta){ + szProto = dat->cache->getActiveProto(); + hContact = dat->cache->getActiveContact(); + } + else { + szProto = dat->szProto; + hContact = dat->hContact; + } + + /* + * editing user notes or preparing a message for queued delivery -> don't send MTN + */ + if (dat->fEditNotesActive || dat->sendMode & SMODE_SENDLATER) + return; + + /* + * allow supression of sending out TN for the contact (NOTE: for metacontacts, do NOT use the subcontact handle) + */ + if (!db_get_b(dat->hContact, SRMSGMOD, SRMSGSET_TYPING, M.GetByte(SRMSGMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW))) + return; + + if (!dat->szProto) // should not, but who knows... + return; + + /* + * check status and capabilities of the protocol + */ + DWORD typeCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_4, 0); + if (!(typeCaps & PF4_SUPPORTTYPING)) + return; + + DWORD protoStatus = CallProtoService(szProto, PS_GETSTATUS, 0, 0); + if (protoStatus < ID_STATUS_ONLINE) + return; + + /* + * check visibility/invisibility lists to not "accidentially" send MTN to contacts who + * should not see them (privacy issue) + */ + DWORD protoCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0); + if (protoCaps & PF1_VISLIST && db_get_w(hContact, szProto, "ApparentMode", 0) == ID_STATUS_OFFLINE) + return; + + if (protoCaps & PF1_INVISLIST && protoStatus == ID_STATUS_INVISIBLE && db_get_w(hContact, szProto, "ApparentMode", 0) != ID_STATUS_ONLINE) + return; + + /* + * don't send to contacts which are not permanently added to the contact list, + * unless the option to ignore added status is set. + */ + if (db_get_b(dat->hContact, "CList", "NotOnList", 0) && !M.GetByte(SRMSGMOD, SRMSGSET_TYPINGUNKNOWN, SRMSGDEFSET_TYPINGUNKNOWN)) + return; + // End user check + dat->nTypeMode = mode; + CallService(MS_PROTO_SELFISTYPING, hContact, dat->nTypeMode); +} + +void TSAPI DM_OptionsApplied(TWindowData *dat, WPARAM wParam, LPARAM lParam) +{ + if (dat == 0) + return; + + HWND hwndDlg = dat->hwnd; + TContainerData *m_pContainer = dat->pContainer; + + dat->szMicroLf[0] = 0; + if (!(dat->pContainer->theme.isPrivate)) { + LoadThemeDefaults(dat->pContainer); + dat->dwFlags = dat->pContainer->theme.dwFlags; + } + LoadLocalFlags(hwndDlg, dat); + + LoadTimeZone(dat); + + dat->showUIElements = m_pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1; + + dat->dwFlagsEx = M.GetByte(dat->hContact, "splitoverride", 0) ? MWF_SHOW_SPLITTEROVERRIDE : 0; + dat->Panel->getVisibility(); + + // small inner margins (padding) for the text areas + SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0, 0)); + SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(3, 3)); + + GetSendFormat(dat, 1); + SetDialogToType(hwndDlg); + SendMessage(hwndDlg, DM_CONFIGURETOOLBAR, 0, 0); + + DM_InitRichEdit(dat); + if (hwndDlg == m_pContainer->hwndActive) + SendMessage(m_pContainer->hwnd, WM_SIZE, 0, 0); + InvalidateRect(GetDlgItem(hwndDlg, IDC_MESSAGE), NULL, FALSE); + if (!lParam) + SendMessage(hwndDlg, DM_REMAKELOG, 0, 0); + + ShowWindow(dat->hwndPanelPicParent, PluginConfig.g_bDisableAniAvatars ? SW_HIDE : SW_SHOW); + EnableWindow(dat->hwndPanelPicParent, PluginConfig.g_bDisableAniAvatars ? FALSE : TRUE); + + SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0); +} + + +void TSAPI DM_Typing(TWindowData *dat, bool fForceOff) +{ + if (dat == 0) + return; + + HWND hwndDlg = dat->hwnd; + HWND hwndContainer = dat->pContainer->hwnd; + HWND hwndStatus = dat->pContainer->hwndStatus; + + if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON && GetTickCount() - dat->nLastTyping > TIMEOUT_TYPEOFF) + DM_NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF); + + if (dat->showTyping == 1) { + if (dat->nTypeSecs > 0) { + dat->nTypeSecs--; + if (GetForegroundWindow() == hwndContainer) + SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0); + } + else { + if (!fForceOff) { + dat->showTyping = 2; + dat->nTypeSecs = 86400; + + mir_sntprintf(dat->szStatusBar, SIZEOF(dat->szStatusBar), TranslateT("%s has entered text."), dat->cache->getNick()); + if (hwndStatus && dat->pContainer->hwndActive == hwndDlg) + SendMessage(hwndStatus, SB_SETTEXT, 0, (LPARAM)dat->szStatusBar); + } + SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0); + HandleIconFeedback(dat, (HICON) - 1); + TWindowData *dat_active = (TWindowData*)GetWindowLongPtr(dat->pContainer->hwndActive, GWLP_USERDATA); + if (dat_active && dat_active->bType == SESSIONTYPE_IM) + SendMessage(hwndContainer, DM_UPDATETITLE, 0, 0); + else + SendMessage(hwndContainer, DM_UPDATETITLE, (WPARAM)dat->pContainer->hwndActive, 1); + if (!(dat->pContainer->dwFlags & CNT_NOFLASH) && PluginConfig.m_FlashOnMTN) + ReflashContainer(dat->pContainer); + } + } + else if (dat->showTyping == 2) { + if (dat->nTypeSecs > 0) + dat->nTypeSecs--; + else { + dat->szStatusBar[0] = 0; + dat->showTyping = 0; + } + UpdateStatusBar(dat); + } + else if (dat->nTypeSecs > 0) { + mir_sntprintf(dat->szStatusBar, SIZEOF(dat->szStatusBar), TranslateT("%s is typing a message"), dat->cache->getNick()); + + dat->nTypeSecs--; + if (hwndStatus && dat->pContainer->hwndActive == hwndDlg) { + SendMessage(hwndStatus, SB_SETTEXT, 0, (LPARAM)dat->szStatusBar); + SendMessage(hwndStatus, SB_SETICON, 0, (LPARAM)PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]); + } + if (IsIconic(hwndContainer) || GetForegroundWindow() != hwndContainer || GetActiveWindow() != hwndContainer) { + SetWindowText(hwndContainer, dat->szStatusBar); + dat->pContainer->dwFlags |= CNT_NEED_UPDATETITLE; + if (!(dat->pContainer->dwFlags & CNT_NOFLASH) && PluginConfig.m_FlashOnMTN) + ReflashContainer(dat->pContainer); + } + + if (dat->pContainer->hwndActive != hwndDlg) { + if (dat->mayFlashTab) + dat->iFlashIcon = PluginConfig.g_IconTypingEvent; + HandleIconFeedback(dat, PluginConfig.g_IconTypingEvent); + } + else { // active tab may show icon if status bar is disabled + if (!hwndStatus) { + if (TabCtrl_GetItemCount(GetParent(hwndDlg)) > 1 || !(dat->pContainer->dwFlags & CNT_HIDETABS)) + HandleIconFeedback(dat, PluginConfig.g_IconTypingEvent); + } + } + if ((GetForegroundWindow() != hwndContainer) || (dat->pContainer->hwndStatus == 0) || (dat->pContainer->hwndActive != hwndDlg)) + SendMessage(hwndContainer, DM_SETICON, (WPARAM)dat, (LPARAM)PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]); + + dat->showTyping = 1; + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// sync splitter position for all open sessions. +// This cares about private / per container / MUC <> IM splitter syncing and everything. +// called from IM and MUC windows via DM_SPLITTERGLOBALEVENT + +int TSAPI DM_SplitterGlobalEvent(TWindowData *dat, WPARAM wParam, LPARAM lParam) +{ + RECT rcWin; + short newMessagePos; + LONG newPos; + TWindowData *srcDat = PluginConfig.lastSPlitterPos.pSrcDat; + TContainerData *srcCnt = PluginConfig.lastSPlitterPos.pSrcContainer; + bool fCntGlobal = (!dat->pContainer->settings->fPrivate ? true : false); + +#if defined(__FEAT_EXP_AUTOSPLITTER) + if (dat->bIsAutosizingInput) + return 0; +#endif + + GetWindowRect(dat->hwnd, &rcWin); + + if (wParam == 0 && lParam == 0) { + if ((dat->dwFlagsEx & MWF_SHOW_SPLITTEROVERRIDE) && dat != srcDat) + return 0; + + if (srcDat->bType == dat->bType) + newPos = PluginConfig.lastSPlitterPos.pos; + else if (srcDat->bType == SESSIONTYPE_IM && dat->bType == SESSIONTYPE_CHAT) + newPos = PluginConfig.lastSPlitterPos.pos + PluginConfig.lastSPlitterPos.off_im; + else if (srcDat->bType == SESSIONTYPE_CHAT && dat->bType == SESSIONTYPE_IM) + newPos = PluginConfig.lastSPlitterPos.pos + PluginConfig.lastSPlitterPos.off_im; + + if (dat == srcDat) { + if (dat->bType == SESSIONTYPE_IM) { + dat->pContainer->settings->splitterPos = dat->splitterY; + if (fCntGlobal) { + SaveSplitter(dat); + if (PluginConfig.lastSPlitterPos.bSync) + g_Settings.iSplitterY = dat->splitterY - DPISCALEY_S(23); + } + } + if (dat->bType == SESSIONTYPE_CHAT) { + SESSION_INFO *si = dat->si; + if (si) { + dat->pContainer->settings->splitterPos = si->iSplitterY + DPISCALEY_S(23); + if (fCntGlobal) { + g_Settings.iSplitterY = si->iSplitterY; + if (PluginConfig.lastSPlitterPos.bSync) + db_set_dw(0, SRMSGMOD_T, "splitsplity", (DWORD)si->iSplitterY + DPISCALEY_S(23)); + } + } + } + return 0; + } + + if (!fCntGlobal && dat->pContainer != srcCnt) + return 0; + if (srcCnt->settings->fPrivate && dat->pContainer != srcCnt) + return 0; + + if (!PluginConfig.lastSPlitterPos.bSync && dat->bType != srcDat->bType) + return 0; + + /* + * for inactive sessions, delay the splitter repositioning until they become + * active (faster, avoid redraw/resize problems for minimized windows) + */ + if (IsIconic(dat->pContainer->hwnd) || dat->pContainer->hwndActive != dat->hwnd) { + dat->dwFlagsEx |= MWF_EX_DELAYEDSPLITTER; + dat->wParam = newPos; + dat->lParam = PluginConfig.lastSPlitterPos.lParam; + return 0; + } + } + else newPos = wParam; + + newMessagePos = (short)rcWin.bottom - (short)newPos; + + if (dat->bType == SESSIONTYPE_IM) { + LoadSplitter(dat); + AdjustBottomAvatarDisplay(dat); + DM_RecalcPictureSize(dat); + SendMessage(dat->hwnd, WM_SIZE, 0, 0); + DM_ScrollToBottom(dat, 1,1); + if (dat != srcDat) + CSkin::UpdateToolbarBG(dat); + } + else { + SESSION_INFO *si = dat->si; + if (si) { + si->iSplitterY = g_Settings.iSplitterY; + SendMessage(dat->hwnd, WM_SIZE, 0, 0); + } + } + return 0; +} + +/** + * incoming event handler + */ + +void TSAPI DM_EventAdded(TWindowData *dat, WPARAM wParam, LPARAM lParam) +{ + TContainerData *m_pContainer = dat->pContainer; + DWORD dwTimestamp = 0; + HWND hwndDlg = dat->hwnd, hwndContainer = m_pContainer->hwnd, hwndTab = GetParent(dat->hwnd); + HANDLE hDbEvent = (HANDLE)lParam; + + DBEVENTINFO dbei = { sizeof(dbei) }; + db_event_get(hDbEvent, &dbei); + if (dat->hDbEventFirst == NULL) + dat->hDbEventFirst = hDbEvent; + + BOOL bIsStatusChangeEvent = IsStatusEvent(dbei.eventType); + + if (dbei.eventType == EVENTTYPE_MESSAGE && (dbei.flags & DBEF_READ)) + return; + + if (!DbEventIsShown(dat, &dbei)) + return; + + if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & (DBEF_SENT))) { + dat->lastMessage = dbei.timestamp; + dat->szStatusBar[0] = 0; + if (dat->showTyping) { + dat->nTypeSecs = 0; + DM_Typing(dat, true); + dat->showTyping = 0; + } + HandleIconFeedback(dat, (HICON)-1); + if (m_pContainer->hwndStatus) + PostMessage(hwndDlg, DM_UPDATELASTMESSAGE, 0, 0); + } + /* + * set the message log divider to mark new (maybe unseen) messages, if the container has + * been minimized or in the background. + */ + if (!(dbei.flags & DBEF_SENT) && !bIsStatusChangeEvent) { + if (PluginConfig.m_DividersUsePopupConfig && PluginConfig.m_UseDividers) { + if (!MessageWindowOpened(dat->hContact, 0)) + SendMessage(hwndDlg, DM_ADDDIVIDER, 0, 0); + } + else if (PluginConfig.m_UseDividers) { + if ((GetForegroundWindow() != hwndContainer || GetActiveWindow() != hwndContainer)) + SendMessage(hwndDlg, DM_ADDDIVIDER, 0, 0); + else { + if (m_pContainer->hwndActive != hwndDlg) + SendMessage(hwndDlg, DM_ADDDIVIDER, 0, 0); + } + } + tabSRMM_ShowPopup(wParam, hDbEvent, dbei.eventType, m_pContainer->fHidden ? 0 : 1, m_pContainer, hwndDlg, dat->cache->getActiveProto(), dat); + if (IsWindowVisible(m_pContainer->hwnd)) + m_pContainer->fHidden = false; + } + dat->cache->updateStats(TSessionStats::UPDATE_WITH_LAST_RCV, 0); + + if (hDbEvent != dat->hDbEventFirst) { + HANDLE nextEvent = db_event_next(dat->hContact, hDbEvent); + if (1 || nextEvent == 0) { + if (!(dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED)) + SendMessage(hwndDlg, DM_APPENDTOLOG, lParam, 0); + else { + TCHAR szBuf[100]; + + if (dat->iNextQueuedEvent >= dat->iEventQueueSize) { + dat->hQueuedEvents = (HANDLE*)mir_realloc(dat->hQueuedEvents, (dat->iEventQueueSize + 10) * sizeof(HANDLE)); + dat->iEventQueueSize += 10; + } + dat->hQueuedEvents[dat->iNextQueuedEvent++] = hDbEvent; + mir_sntprintf(szBuf, SIZEOF(szBuf), TranslateT("Autoscrolling is disabled, %d message(s) queued (press F12 to enable it)"), + dat->iNextQueuedEvent); + SetDlgItemText(hwndDlg, IDC_LOGFROZENTEXT, szBuf); + RedrawWindow(GetDlgItem(hwndDlg, IDC_LOGFROZENTEXT), NULL, NULL, RDW_INVALIDATE); + } + } + else SendMessage(hwndDlg, DM_REMAKELOG, 0, 0); + } + else SendMessage(hwndDlg, DM_REMAKELOG, 0, 0); + + // handle tab flashing + if ((TabCtrl_GetCurSel(hwndTab) != dat->iTabID) && !(dbei.flags & DBEF_SENT) && !bIsStatusChangeEvent) { + switch (dbei.eventType) { + case EVENTTYPE_MESSAGE: + dat->iFlashIcon = PluginConfig.g_IconMsgEvent; + break; + case EVENTTYPE_FILE: + dat->iFlashIcon = PluginConfig.g_IconFileEvent; + break; + default: + dat->iFlashIcon = PluginConfig.g_IconMsgEvent; + break; + } + SetTimer(hwndDlg, TIMERID_FLASHWND, TIMEOUT_FLASHWND, NULL); + dat->mayFlashTab = TRUE; + } + /* + * try to flash the contact list... + */ + FlashOnClist(hwndDlg, dat, hDbEvent, &dbei); + + /* + * autoswitch tab if option is set AND container is minimized (otherwise, we never autoswitch) + * never switch for status changes... + */ + if (!(dbei.flags & DBEF_SENT) && !bIsStatusChangeEvent) { + if (PluginConfig.haveAutoSwitch() && m_pContainer->hwndActive != hwndDlg) { + if ((IsIconic(hwndContainer) && !IsZoomed(hwndContainer)) || (PluginConfig.m_HideOnClose && !IsWindowVisible(m_pContainer->hwnd))) { + int iItem = GetTabIndexFromHWND(GetParent(hwndDlg), hwndDlg); + if (iItem >= 0) { + TabCtrl_SetCurSel(GetParent(hwndDlg), iItem); + ShowWindow(m_pContainer->hwndActive, SW_HIDE); + m_pContainer->hwndActive = hwndDlg; + SendMessage(hwndContainer, DM_UPDATETITLE, dat->hContact, 0); + m_pContainer->dwFlags |= CNT_DEFERREDTABSELECT; + } + } + } + } + + /* + * flash window if it is not focused + */ + if ((GetActiveWindow() != hwndContainer || GetForegroundWindow() != hwndContainer || dat->pContainer->hwndActive != hwndDlg) && !(dbei.flags & DBEF_SENT) && !bIsStatusChangeEvent) { + if (!(m_pContainer->dwFlags & CNT_NOFLASH) && (GetActiveWindow() != hwndContainer || GetForegroundWindow() != hwndContainer)) + FlashContainer(m_pContainer, 1, 0); + SendMessage(hwndContainer, DM_SETICON, (WPARAM)dat, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_MESSAGE)); + m_pContainer->dwFlags |= CNT_NEED_UPDATETITLE; + } + + /* + * play a sound + */ + if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & (DBEF_SENT))) + PostMessage(hwndDlg, DM_PLAYINCOMINGSOUND, 0, 0); + + if (dat->pWnd) + dat->pWnd->Invalidate(); +} + +void TSAPI DM_HandleAutoSizeRequest(TWindowData *dat, REQRESIZE* rr) +{ + if (dat == NULL || rr == NULL || GetForegroundWindow() != dat->pContainer->hwnd) + return; + + if (!dat->bIsAutosizingInput || dat->iInputAreaHeight == -1) + return; + + LONG heightLimit = M.GetDword("autoSplitMinLimit", 0); + LONG iNewHeight = rr->rc.bottom - rr->rc.top; + + if (CSkin::m_skinEnabled && !SkinItems[ID_EXTBKINPUTAREA].IGNORED) + iNewHeight += (SkinItems[ID_EXTBKINPUTAREA].MARGIN_TOP + SkinItems[ID_EXTBKINPUTAREA].MARGIN_BOTTOM - 2); + + if (heightLimit && iNewHeight < heightLimit) + iNewHeight = heightLimit; + + if (iNewHeight == dat->iInputAreaHeight) + return; + + RECT rc; + GetClientRect(dat->hwnd, &rc); + LONG cy = rc.bottom - rc.top; + LONG panelHeight = (dat->Panel->isActive() ? dat->Panel->getHeight() : 0); + + if (iNewHeight > (cy - panelHeight) / 2) + iNewHeight = (cy - panelHeight) / 2; + + if (dat->bType == SESSIONTYPE_IM) { + dat->dynaSplitter = rc.bottom - (rc.bottom - iNewHeight + DPISCALEY_S(2)); + if (dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR) + dat->dynaSplitter += DPISCALEY_S(22); + dat->splitterY = dat->dynaSplitter + DPISCALEY_S(34); + DM_RecalcPictureSize(dat); + } + else if (dat->si) { + dat->si->iSplitterY = (rc.bottom - (rc.bottom - iNewHeight + DPISCALEY_S(3))) + DPISCALEY_S(34); + if (!(dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR)) + dat->si->iSplitterY -= DPISCALEY_S(22); + SendMessage(dat->hwnd, WM_SIZE, 0, 0); + } + dat->iInputAreaHeight = iNewHeight; + CSkin::UpdateToolbarBG(dat); + DM_ScrollToBottom(dat, 1, 0); +} + +void TSAPI DM_UpdateTitle(TWindowData *dat, WPARAM wParam, LPARAM lParam) +{ + TCHAR newtitle[128], newcontactname[128]; + DWORD dwOldIdle = dat->idle; + const char *szActProto = 0; + + HWND hwndDlg = dat->hwnd; + HWND hwndTab = GetParent(hwndDlg); + HWND hwndContainer = dat->pContainer->hwnd; + TContainerData* m_pContainer = dat->pContainer; + + newcontactname[0] = 0; + dat->szStatus[0] = 0; + + if (dat->iTabID == -1) + return; + + TCITEM item = { 0 }; + + if (dat->hContact) { + const TCHAR *szNick = dat->cache->getNick(); + + if (dat->szProto) { + szActProto = dat->cache->getProto(); + MCONTACT hActContact = dat->hContact; + + bool bHasName = (dat->cache->getUIN()[0] != 0); + dat->idle = dat->cache->getIdleTS(); + dat->dwFlagsEx = dat->idle ? dat->dwFlagsEx | MWF_SHOW_ISIDLE : dat->dwFlagsEx & ~MWF_SHOW_ISIDLE; + + dat->wStatus = dat->cache->getStatus(); + _tcsncpy_s(dat->szStatus, SIZEOF(dat->szStatus), pcli->pfnGetStatusModeDescription(dat->szProto == NULL ? ID_STATUS_OFFLINE : dat->wStatus, 0), _TRUNCATE); + + if (lParam != 0) { + if (PluginConfig.m_CutContactNameOnTabs) + CutContactName(szNick, newcontactname, SIZEOF(newcontactname)); + else + lstrcpyn(newcontactname, szNick, SIZEOF(newcontactname)); + + Utils::DoubleAmpersands(newcontactname); + + if (lstrlen(newcontactname) != 0 && dat->szStatus != NULL) { + if (PluginConfig.m_StatusOnTabs) + mir_sntprintf(newtitle, 127, _T("%s (%s)"), newcontactname, dat->szStatus); + else + mir_sntprintf(newtitle, 127, _T("%s"), newcontactname); + } + else mir_sntprintf(newtitle, 127, _T("%s"), _T("Forward")); + + item.mask |= TCIF_TEXT; + } + SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0); + + TCHAR fulluin[256]; + if (dat->bIsMeta) + mir_sntprintf(fulluin, SIZEOF(fulluin), + TranslateT("UID: %s (SHIFT click -> copy to clipboard)\nClick for User's Details\nRight click for MetaContact control\nClick dropdown to add or remove user from your favorites."), + bHasName ? dat->cache->getUIN() : TranslateT("No UID")); + else + mir_sntprintf(fulluin, SIZEOF(fulluin), + TranslateT("UID: %s (SHIFT click -> copy to clipboard)\nClick for User's Details\nClick dropdown to change this contact's favorite status."), + bHasName ? dat->cache->getUIN() : TranslateT("No UID")); + + SendMessage(GetDlgItem(hwndDlg, IDC_NAME), BUTTONADDTOOLTIP, (WPARAM)fulluin, BATF_TCHAR); + } + } + else lstrcpyn(newtitle, _T("Message Session"), SIZEOF(newtitle)); + + if (dat->idle != dwOldIdle || lParam != 0) { + if (item.mask & TCIF_TEXT) { + item.pszText = newtitle; + _tcsncpy(dat->newtitle, newtitle, SIZEOF(dat->newtitle)); + dat->newtitle[127] = 0; + item.cchTextMax = 127; + if (dat->pWnd) + dat->pWnd->updateTitle(dat->cache->getNick()); + } + if (dat->iTabID >= 0) { + TabCtrl_SetItem(hwndTab, dat->iTabID, &item); + if (m_pContainer->dwFlags & CNT_SIDEBAR) + m_pContainer->SideBar->updateSession(dat); + } + if (m_pContainer->hwndActive == hwndDlg && lParam) + SendMessage(hwndContainer, DM_UPDATETITLE, dat->hContact, 0); + + UpdateTrayMenuState(dat, TRUE); + if (dat->cache->isFavorite()) + AddContactToFavorites(dat->hContact, dat->cache->getNick(), szActProto, dat->szStatus, dat->wStatus, + LoadSkinnedProtoIcon(dat->cache->getProto(), dat->cache->getStatus()), 0, PluginConfig.g_hMenuFavorites); + + if (dat->cache->isRecent()) + AddContactToFavorites(dat->hContact, dat->cache->getNick(), szActProto, dat->szStatus, dat->wStatus, + LoadSkinnedProtoIcon(dat->cache->getProto(), dat->cache->getStatus()), 0, PluginConfig.g_hMenuRecent); + + dat->Panel->Invalidate(); + if (dat->pWnd) + dat->pWnd->Invalidate(); + + if (PluginConfig.g_FlashAvatarAvail) { + FLASHAVATAR fa = {0}; + + fa.hContact = dat->hContact; + fa.hWindow = 0; + fa.id = 25367; + fa.cProto = dat->szProto; + + CallService(MS_FAVATAR_GETINFO, (WPARAM)&fa, 0); + dat->hwndFlash = fa.hWindow; + if (dat->hwndFlash) + SetParent(dat->hwndFlash, dat->Panel->isActive() ? dat->hwndPanelPicParent : GetDlgItem(hwndDlg, IDC_CONTACTPIC)); + } + } + // care about MetaContacts and update the statusbar icon with the currently "most online" contact... + if (dat->bIsMeta) { + PostMessage(hwndDlg, DM_UPDATEMETACONTACTINFO, 0, 0); + PostMessage(hwndDlg, DM_OWNNICKCHANGED, 0, 0); + if (m_pContainer->dwFlags & CNT_UINSTATUSBAR) + DM_UpdateLastMessage(dat); + } +} + +/* +* status icon stuff (by sje, used for indicating encryption status in the status bar +* this is now part of the message window api +*/ + +static HANDLE hHookIconPressedEvt; + +static int OnSrmmIconChanged(WPARAM hContact, LPARAM) +{ + if (hContact == NULL) + M.BroadcastMessage(DM_STATUSICONCHANGE, 0, 0); + else { + HWND hwnd = M.FindWindow(hContact); + if (hwnd) + PostMessage(hwnd, DM_STATUSICONCHANGE, 0, 0); + } + return 0; +} + +void DrawStatusIcons(TWindowData *dat, HDC hDC, RECT r, int gap) +{ + HICON hIcon = NULL; + int x = r.left; + LONG cx_icon = PluginConfig.m_smcxicon; + LONG cy_icon = PluginConfig.m_smcyicon; + LONG y = (r.top + r.bottom - cx_icon) >> 1; + + SetBkMode(hDC, TRANSPARENT); + + int nIcon = 0; + while (StatusIconData *si = Srmm_GetNthIcon(dat->hContact, nIcon++)) { + if ( !strcmp(si->szModule, MSG_ICON_MODULE)) { + if (si->dwId == MSG_ICON_SOUND) { + DrawIconEx(hDC, x, y, PluginConfig.g_buttonBarIcons[ICON_DEFAULT_SOUNDS], + cx_icon, cy_icon, 0, NULL, DI_NORMAL); + + DrawIconEx(hDC, x, y, dat->pContainer->dwFlags & CNT_NOSOUND ? + PluginConfig.g_iconOverlayDisabled : PluginConfig.g_iconOverlayEnabled, + cx_icon, cy_icon, 0, NULL, DI_NORMAL); + } + else if (si->dwId == MSG_ICON_UTN) { + if (dat->bType == SESSIONTYPE_IM) { + DrawIconEx(hDC, x, y, PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING], cx_icon, cy_icon, 0, NULL, DI_NORMAL); + + DrawIconEx(hDC, x, y, db_get_b(dat->hContact, SRMSGMOD, SRMSGSET_TYPING, M.GetByte(SRMSGMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW)) ? + PluginConfig.g_iconOverlayEnabled : PluginConfig.g_iconOverlayDisabled, cx_icon, cy_icon, 0, NULL, DI_NORMAL); + } + else CSkin::DrawDimmedIcon(hDC, x, y, cx_icon, cy_icon, PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING], 50); + } + else if (si->dwId == MSG_ICON_SESSION) { + DrawIconEx(hDC, x, y, PluginConfig.g_sideBarIcons[0], cx_icon, cy_icon, 0, NULL, DI_NORMAL); + } + } + else { + if ((si->flags & MBF_DISABLED) && si->hIconDisabled) + hIcon = si->hIconDisabled; + else + hIcon = si->hIcon; + + if ((si->flags & MBF_DISABLED) && si->hIconDisabled == NULL) + CSkin::DrawDimmedIcon(hDC, x, y, cx_icon, cy_icon, hIcon, 50); + else + DrawIconEx(hDC, x, y, hIcon, 16, 16, 0, NULL, DI_NORMAL); + } + + x += cx_icon + gap; + } +} + +void SI_CheckStatusIconClick(TWindowData *dat, HWND hwndFrom, POINT pt, RECT r, int gap, int code) +{ + if (dat && (code == NM_CLICK || code == NM_RCLICK)) { + POINT ptScreen; + GetCursorPos(&ptScreen); + if (!PtInRect(&rcLastStatusBarClick, ptScreen)) + return; + } + + UINT iconNum = (pt.x - (r.left + 0)) / (PluginConfig.m_smcxicon + gap), list_icons = 0; + StatusIconData *si = Srmm_GetNthIcon((dat) ? dat->hContact : 0, iconNum); + if (si == NULL) + return; + + if ( !strcmp(si->szModule, MSG_ICON_MODULE)) { + if (si->dwId == MSG_ICON_SOUND && code != NM_RCLICK) { + if (GetKeyState(VK_SHIFT) & 0x8000) { + for (TContainerData *p = pFirstContainer; p; p = p->pNext) { + p->dwFlags = ((dat->pContainer->dwFlags & CNT_NOSOUND) ? p->dwFlags | CNT_NOSOUND : p->dwFlags & ~CNT_NOSOUND); + InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE); + } + } + else { + dat->pContainer->dwFlags ^= CNT_NOSOUND; + InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE); + } + } + else if (si->dwId == MSG_ICON_UTN && code != NM_RCLICK && dat->bType == SESSIONTYPE_IM) { + SendMessage(dat->pContainer->hwndActive, WM_COMMAND, IDC_SELFTYPING, 0); + InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE); + } + else if (si->dwId == MSG_ICON_SESSION) { + if (code == NM_CLICK) + PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_TRAYICONNOTIFY, 101, WM_LBUTTONUP); + else if (code == NM_RCLICK) + PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_TRAYICONNOTIFY, 101, WM_RBUTTONUP); + } + } + else { + StatusIconClickData sicd = { sizeof(sicd) }; + GetCursorPos(&sicd.clickLocation); + sicd.dwId = si->dwId; + sicd.szModule = si->szModule; + sicd.flags = (code == NM_RCLICK ? MBCF_RIGHTBUTTON : 0); + NotifyEventHooks(hHookIconPressedEvt, dat->hContact, (LPARAM)&sicd); + InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE); + } +} + +int SI_InitStatusIcons() +{ + StatusIconData sid = { sizeof(sid) }; + sid.szModule = MSG_ICON_MODULE; + sid.dwId = MSG_ICON_SOUND; // Sounds + Srmm_AddIcon(&sid); + + sid.dwId = MSG_ICON_UTN; + Srmm_AddIcon(&sid); + + sid.dwId = MSG_ICON_SESSION; + Srmm_AddIcon(&sid); + + HookEvent(ME_MSG_ICONSCHANGED, OnSrmmIconChanged); + + hHookIconPressedEvt = CreateHookableEvent(ME_MSG_ICONPRESSED); + return 0; +} + +int SI_DeinitStatusIcons() +{ + DestroyHookableEvent(hHookIconPressedEvt); + return 0; +} diff --git a/plugins/TabSRMM/src/mim.cpp b/plugins/TabSRMM/src/mim.cpp index d6a45b2aa1..649ed59f93 100644 --- a/plugins/TabSRMM/src/mim.cpp +++ b/plugins/TabSRMM/src/mim.cpp @@ -1,672 +1,672 @@ -/* - * Miranda NG: the free IM client for Microsoft* Windows* - * - * Copyright (c) 2000-09 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. - * - * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors - * - * wraps some parts of Miranda API - * Also, OS dependent stuff (visual styles api etc.) - * - */ - -#include "commonheaders.h" - -PDTTE CMimAPI::m_pfnDrawThemeTextEx = 0; -DEFICA CMimAPI::m_pfnDwmExtendFrameIntoClientArea = 0; -DICE CMimAPI::m_pfnDwmIsCompositionEnabled = 0; -DRT CMimAPI::m_pfnDwmRegisterThumbnail = 0; -BPI CMimAPI::m_pfnBufferedPaintInit = 0; -BPU CMimAPI::m_pfnBufferedPaintUninit = 0; -BBP CMimAPI::m_pfnBeginBufferedPaint = 0; -EBP CMimAPI::m_pfnEndBufferedPaint = 0; -BBW CMimAPI::m_pfnDwmBlurBehindWindow = 0; -DGC CMimAPI::m_pfnDwmGetColorizationColor = 0; -BPSA CMimAPI::m_pfnBufferedPaintSetAlpha = 0; -DWMIIB CMimAPI::m_pfnDwmInvalidateIconicBitmaps = 0; -DWMSWA CMimAPI::m_pfnDwmSetWindowAttribute = 0; -DWMUT CMimAPI::m_pfnDwmUpdateThumbnailProperties = 0; -DURT CMimAPI::m_pfnDwmUnregisterThumbnail = 0; -DSIT CMimAPI::m_pfnDwmSetIconicThumbnail = 0; -DSILP CMimAPI::m_pfnDwmSetIconicLivePreviewBitmap = 0; -bool CMimAPI::m_shutDown = 0; -TCHAR CMimAPI::m_userDir[] = _T("\0"); - -bool CMimAPI::m_haveBufferedPaint = false; - -/** - * Case insensitive _tcsstr - * - * @param szString TCHAR *: String to be searched - * @param szSearchFor - *TCHAR *: String that should be found in szString - * - * @return TCHAR *: found position of szSearchFor in szString. 0 if szSearchFor was not found - */ -const TCHAR* CMimAPI::StriStr(const TCHAR *szString, const TCHAR *szSearchFor) -{ - assert(szString != 0 && szSearchFor != 0); - - if (!szString || *szString == 0) - return NULL; - - if (!szSearchFor || *szSearchFor == 0) - return szString; - - for (; *szString; ++szString) { - if (_totupper(*szString) == _totupper(*szSearchFor)) { - const TCHAR *h, *n; - for (h = szString, n = szSearchFor; *h && *n; ++h, ++n) - if (_totupper(*h) != _totupper(*n)) - break; - - if (!*n) - return szString; - } - } - return NULL; -} - -int CMimAPI::pathIsAbsolute(const TCHAR *path) const -{ - if (!path || !(lstrlen(path) > 2)) - return 0; - if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\')) - return 1; - return 0; -} - -size_t CMimAPI::pathToRelative(const TCHAR *pSrc, TCHAR *pOut, const TCHAR *szBase) const -{ - const TCHAR *tszBase = szBase ? szBase : m_szProfilePath; - - pOut[0] = 0; - if (!pSrc || !lstrlen(pSrc) || lstrlen(pSrc) > MAX_PATH) - return 0; - if (!pathIsAbsolute(pSrc)) { - mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc); - return lstrlen(pOut); - } - - TCHAR szTmp[MAX_PATH]; - mir_sntprintf(szTmp, SIZEOF(szTmp), _T("%s"), pSrc); - if (StriStr(szTmp, tszBase)) { - if (tszBase[lstrlen(tszBase) - 1] == '\\') - mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc + lstrlen(tszBase)); - else { - mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc + lstrlen(tszBase) + 1 ); - //pOut[0]='.'; - } - return(lstrlen(pOut)); - } - - mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc); - return(lstrlen(pOut)); -} - -/** - * Translate a relativ path to an absolute, using the current profile - * data directory. - * - * @param pSrc TCHAR *: input path + filename (relative) - * @param pOut TCHAR *: the result - * @param szBase TCHAR *: (OPTIONAL) base path for the translation. Can be 0 in which case - * the function will use m_szProfilePath (usually \tabSRMM below %miranda_userdata% - * - * @return - */ -size_t CMimAPI::pathToAbsolute(const TCHAR *pSrc, TCHAR *pOut, const TCHAR *szBase) const -{ - const TCHAR *tszBase = szBase ? szBase : m_szProfilePath; - - pOut[0] = 0; - if (!pSrc || !lstrlen(pSrc) || lstrlen(pSrc) > MAX_PATH) - return 0; - if (pathIsAbsolute(pSrc) && pSrc[0]!='.') - mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc); - else if (pSrc[0]=='.') - mir_sntprintf(pOut, MAX_PATH, _T("%s\\%s"), tszBase, pSrc + 1); - else - mir_sntprintf(pOut, MAX_PATH, _T("%s\\%s"), tszBase, pSrc); - - return lstrlen(pOut); -} - -/* - * window list functions - */ - -void CMimAPI::BroadcastMessage(UINT msg, WPARAM wParam, LPARAM lParam) -{ - WindowList_Broadcast(m_hMessageWindowList, msg, wParam, lParam); -} - -void CMimAPI::BroadcastMessageAsync(UINT msg, WPARAM wParam, LPARAM lParam) -{ - WindowList_BroadcastAsync(m_hMessageWindowList, msg, wParam, lParam); -} - -HWND CMimAPI::FindWindow(MCONTACT h) const -{ - return WindowList_Find(m_hMessageWindowList, h); -} - -INT_PTR CMimAPI::AddWindow(HWND hWnd, MCONTACT h) -{ - return WindowList_Add(m_hMessageWindowList, hWnd, h); -} - -INT_PTR CMimAPI::RemoveWindow(HWND hWnd) -{ - return WindowList_Remove(m_hMessageWindowList, hWnd); -} - -int CMimAPI::FoldersPathChanged(WPARAM wParam, LPARAM lParam) -{ - return M.foldersPathChanged(); -} - -void CMimAPI::configureCustomFolders() -{ - m_hDataPath = FoldersRegisterCustomPathT(LPGEN("TabSRMM"), LPGEN("Data path"), const_cast(getDataPath())); - m_hSkinsPath = FoldersRegisterCustomPathT(LPGEN("Skins"), LPGEN("TabSRMM"), const_cast(getSkinPath())); - m_hAvatarsPath = FoldersRegisterCustomPathT(LPGEN("Avatars"), LPGEN("Saved TabSRMM avatars"), const_cast(getSavedAvatarPath())); - m_hChatLogsPath = FoldersRegisterCustomPathT(LPGEN("TabSRMM"), LPGEN("Group chat logs root"), const_cast(getChatLogPath())); - - if (m_hDataPath) - HookEvent(ME_FOLDERS_PATH_CHANGED, CMimAPI::FoldersPathChanged); - - foldersPathChanged(); -} - -INT_PTR CMimAPI::foldersPathChanged() -{ - TCHAR szTemp[MAX_PATH + 2] = {'\0'}; - - if (m_hDataPath) { - FoldersGetCustomPathT(m_hDataPath, szTemp, MAX_PATH, const_cast(getDataPath())); - mir_sntprintf(m_szProfilePath, MAX_PATH, _T("%s"), szTemp); - - FoldersGetCustomPathT(m_hSkinsPath, szTemp, MAX_PATH, const_cast(getSkinPath())); - mir_sntprintf(m_szSkinsPath, MAX_PATH - 1, _T("%s"), szTemp); - Utils::ensureTralingBackslash(m_szSkinsPath); - - FoldersGetCustomPathT(m_hAvatarsPath, szTemp, MAX_PATH, const_cast(getSavedAvatarPath())); - mir_sntprintf(m_szSavedAvatarsPath, MAX_PATH, _T("%s"), szTemp); - - FoldersGetCustomPathT(m_hChatLogsPath, szTemp, MAX_PATH, const_cast(getChatLogPath())); - mir_sntprintf(m_szChatLogsPath, MAX_PATH, _T("%s"), szTemp); - Utils::ensureTralingBackslash(m_szChatLogsPath); - } - - CreateDirectoryTreeT(m_szProfilePath); - CreateDirectoryTreeT(m_szSkinsPath); - CreateDirectoryTreeT(m_szSavedAvatarsPath); - - Skin->extractSkinsAndLogo(true); - Skin->setupAeroSkins(); - return 0; -} - -const TCHAR* CMimAPI::getUserDir() -{ - if (m_userDir[0] == 0) { - if ( ServiceExists(MS_FOLDERS_REGISTER_PATH)) - lstrcpyn(m_userDir, L"%miranda_userdata%", SIZEOF(m_userDir)); - else - lstrcpyn(m_userDir, VARST( _T("%miranda_userdata%")), SIZEOF(m_userDir)); - - Utils::ensureTralingBackslash(m_userDir); - } - return m_userDir; -} - -void CMimAPI::InitPaths() -{ - m_szProfilePath[0] = 0; - m_szSkinsPath[0] = 0; - m_szSavedAvatarsPath[0] = 0; - - const TCHAR *szUserdataDir = getUserDir(); - - mir_sntprintf(m_szProfilePath, MAX_PATH, _T("%stabSRMM"), szUserdataDir); - if (ServiceExists(MS_FOLDERS_REGISTER_PATH)) { - lstrcpyn(m_szChatLogsPath, _T("%miranda_logpath%"), MAX_PATH); - lstrcpyn(m_szSkinsPath, _T("%miranda_path%\\Skins\\TabSRMM"), MAX_PATH); - } - else { - lstrcpyn(m_szChatLogsPath, VARST(_T("%miranda_logpath%")), MAX_PATH); - lstrcpyn(m_szSkinsPath, VARST(_T("%miranda_path%\\Skins\\TabSRMM")), MAX_PATH); - } - - Utils::ensureTralingBackslash(m_szChatLogsPath); - replaceStrT(g_Settings.pszLogDir, m_szChatLogsPath); - - Utils::ensureTralingBackslash(m_szSkinsPath); - - mir_sntprintf(m_szSavedAvatarsPath, MAX_PATH, _T("%s\\Saved Contact Pictures"), m_szProfilePath); -} - -bool CMimAPI::getAeroState() -{ - BOOL result = FALSE; - m_isAero = m_DwmActive = false; - if (IsWinVerVistaPlus()) { - m_DwmActive = (m_pfnDwmIsCompositionEnabled && (m_pfnDwmIsCompositionEnabled(&result) == S_OK) && result) ? true : false; - m_isAero = (CSkin::m_skinEnabled == false) && GetByte("useAero", 1) && CSkin::m_fAeroSkinsValid && m_DwmActive; - - } - m_isVsThemed = IsThemeActive() != 0; - return m_isAero; -} - -/** - * Initialize various Win32 API functions which are not common to all versions of Windows. - * We have to work with functions pointers here. - */ - -void CMimAPI::InitAPI() -{ - m_hUxTheme = 0; - - /* - * vista+ DWM API - */ - m_hDwmApi = 0; - if (IsWinVerVistaPlus()) { - m_hDwmApi = Utils::loadSystemLibrary(L"\\dwmapi.dll"); - if (m_hDwmApi) { - m_pfnDwmExtendFrameIntoClientArea = (DEFICA)GetProcAddress(m_hDwmApi,"DwmExtendFrameIntoClientArea"); - m_pfnDwmIsCompositionEnabled = (DICE)GetProcAddress(m_hDwmApi,"DwmIsCompositionEnabled"); - m_pfnDwmRegisterThumbnail = (DRT)GetProcAddress(m_hDwmApi, "DwmRegisterThumbnail"); - m_pfnDwmBlurBehindWindow = (BBW)GetProcAddress(m_hDwmApi, "DwmEnableBlurBehindWindow"); - m_pfnDwmGetColorizationColor = (DGC)GetProcAddress(m_hDwmApi, "DwmGetColorizationColor"); - m_pfnDwmInvalidateIconicBitmaps = (DWMIIB)GetProcAddress(m_hDwmApi, "DwmInvalidateIconicBitmaps"); - m_pfnDwmSetWindowAttribute = (DWMSWA)GetProcAddress(m_hDwmApi, "DwmSetWindowAttribute"); - m_pfnDwmUpdateThumbnailProperties = (DWMUT)GetProcAddress(m_hDwmApi, "DwmUpdateThumbnailProperties"); - m_pfnDwmUnregisterThumbnail = (DURT)GetProcAddress(m_hDwmApi, "DwmUnregisterThumbnail"); - m_pfnDwmSetIconicThumbnail = (DSIT)GetProcAddress(m_hDwmApi, "DwmSetIconicThumbnail"); - m_pfnDwmSetIconicLivePreviewBitmap = (DSILP)GetProcAddress(m_hDwmApi, "DwmSetIconicLivePreviewBitmap"); - } - /* - * additional uxtheme APIs (Vista+) - */ - m_hUxTheme = Utils::loadSystemLibrary(L"\\uxtheme.dll"); - if (m_hUxTheme) { - m_pfnDrawThemeTextEx = (PDTTE)GetProcAddress(m_hUxTheme, "DrawThemeTextEx"); - m_pfnBeginBufferedPaint = (BBP)GetProcAddress(m_hUxTheme, "BeginBufferedPaint"); - m_pfnEndBufferedPaint = (EBP)GetProcAddress(m_hUxTheme, "EndBufferedPaint"); - m_pfnBufferedPaintInit = (BPI)GetProcAddress(m_hUxTheme, "BufferedPaintInit"); - m_pfnBufferedPaintUninit = (BPU)GetProcAddress(m_hUxTheme, "BufferedPaintUnInit"); - m_pfnBufferedPaintSetAlpha = (BPSA)GetProcAddress(m_hUxTheme, "BufferedPaintSetAlpha"); - m_haveBufferedPaint = (m_pfnBeginBufferedPaint != 0 && m_pfnEndBufferedPaint != 0) ? true : false; - if (m_haveBufferedPaint) - m_pfnBufferedPaintInit(); - } - } - else m_haveBufferedPaint = false; -} - -/** - * hook subscriber function for incoming message typing events - */ - -int CMimAPI::TypingMessage(WPARAM hContact, LPARAM lParam) -{ - HWND hwnd = 0; - int issplit = 1, foundWin = 0, preTyping = 0; - BOOL fShowOnClist = TRUE; - - if (hContact) { - if ((hwnd = M.FindWindow(hContact)) && M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPING, SRMSGDEFSET_SHOWTYPING)) - preTyping = SendMessage(hwnd, DM_TYPING, 0, lParam); - - if (hwnd && IsWindowVisible(hwnd)) - foundWin = MessageWindowOpened(0, (LPARAM)hwnd); - else - foundWin = 0; - - TContainerData *pContainer = NULL; - if (hwnd) { - SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pContainer); - if (pContainer == NULL) - return 0; // should never happen - } - - if ( M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGCLIST, SRMSGDEFSET_SHOWTYPINGCLIST)) { - if (!hwnd && !M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGNOWINOPEN, 1)) - fShowOnClist = FALSE; - if (hwnd && !M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGWINOPEN, 1)) - fShowOnClist = FALSE; - } - else fShowOnClist = FALSE; - - if ((!foundWin || !(pContainer->dwFlags & CNT_NOSOUND)) && preTyping != (lParam != 0)) - SkinPlaySound((lParam) ? "TNStart" : "TNStop"); - - if (M.GetByte(SRMSGMOD, "ShowTypingPopup", 0)) { - BOOL fShow = FALSE; - int iMode = M.GetByte("MTN_PopupMode", 0); - - switch(iMode) { - case 0: - fShow = TRUE; - break; - case 1: - if (!foundWin || !(pContainer && pContainer->hwndActive == hwnd && GetForegroundWindow() == pContainer->hwnd)) - fShow = TRUE; - break; - case 2: - if (hwnd == 0) - fShow = TRUE; - else { - if (PluginConfig.m_HideOnClose) { - TContainerData *pContainer = 0; - SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pContainer); - if (pContainer && pContainer->fHidden) - fShow = TRUE; - } - } - break; - } - if (fShow) - TN_TypingMessage(hContact, lParam); - } - - if (lParam) { - TCHAR szTip[256]; - mir_sntprintf(szTip, SIZEOF(szTip), TranslateT("%s is typing a message."), pcli->pfnGetContactDisplayName(hContact, 0)); - if (fShowOnClist && ServiceExists(MS_CLIST_SYSTRAY_NOTIFY) && M.GetByte(SRMSGMOD, "ShowTypingBalloon", 0)) { - MIRANDASYSTRAYNOTIFY tn; - tn.szProto = NULL; - tn.cbSize = sizeof(tn); - tn.tszInfoTitle = TranslateT("Typing Notification"); - tn.tszInfo = szTip; - tn.dwInfoFlags = NIIF_INFO | NIIF_INTERN_UNICODE; - tn.uTimeout = 1000 * 4; - CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM)&tn); - } - if (fShowOnClist) { - CLISTEVENT cle = { sizeof(cle) }; - cle.hContact = hContact; - cle.hDbEvent = (HANDLE)1; - cle.flags = CLEF_ONLYAFEW | CLEF_TCHAR; - cle.hIcon = PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]; - cle.pszService = "SRMsg/TypingMessage"; - cle.ptszTooltip = szTip; - CallServiceSync(MS_CLIST_REMOVEEVENT, hContact, 1); - CallServiceSync(MS_CLIST_ADDEVENT, hContact, (LPARAM)&cle); - } - } - } - return 0; -} - -/** - * this is the global ack dispatcher. It handles both ACKTYPE_MESSAGE and ACKTYPE_AVATAR events - * for ACKTYPE_MESSAGE it searches the corresponding send job in the queue and, if found, dispatches - * it to the owners window - * - * ACKTYPE_AVATAR no longer handled here, because we have avs services now. - */ - -int CMimAPI::ProtoAck(WPARAM wParam, LPARAM lParam) -{ - ACKDATA *pAck = (ACKDATA*)lParam; - if (lParam == 0) - return 0; - - HWND hwndDlg = 0; - int i=0, iFound = SendQueue::NR_SENDJOBS; - SendJob *jobs = sendQueue->getJobByIndex(0); - - if (pAck->type == ACKTYPE_MESSAGE) { - MCONTACT hMeta = db_mc_getMeta(pAck->hContact); - for (int j = 0; j < SendQueue::NR_SENDJOBS; j++) { - SendJob &p = jobs[j]; - if (pAck->hProcess == p.hSendId && pAck->hContact == p.hOwner) { - TWindowData *dat = p.hwndOwner ? (TWindowData*)GetWindowLongPtr(p.hwndOwner, GWLP_USERDATA) : NULL; - if (dat == NULL) { - sendQueue->ackMessage(NULL, (WPARAM)MAKELONG(j, i), lParam); - return 0; - } - if (dat->hContact == p.hOwner || dat->hContact == hMeta) { - iFound = j; - break; - } - } - if (iFound != SendQueue::NR_SENDJOBS) // no mathing entry found in this queue entry.. continue - break; - } - if (iFound == SendQueue::NR_SENDJOBS) // no matching send info found in the queue - sendLater->processAck(pAck); - else // try to find the process handle in the list of open send later jobs - SendMessage(jobs[iFound].hwndOwner, HM_EVENTSENT, (WPARAM)MAKELONG(iFound, i), lParam); - } - return 0; -} - -int CMimAPI::PrebuildContactMenu(WPARAM hContact, LPARAM lParam) -{ - if (hContact == NULL) - return NULL; - - bool bEnabled = false; - char *szProto = GetContactProto(hContact); - if (szProto) { - // leave this menu item hidden for chats - if ( !db_get_b(hContact, szProto, "ChatRoom", 0 )) - if ( CallProtoService( szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IMSEND) - bEnabled = true; - } - - Menu_ShowItem(PluginConfig.m_hMenuItem, bEnabled); - return 0; -} - -/** - * this handler is called first in the message window chain - it will handle events for which a message window - * is already open. if not, it will do nothing and the 2nd handler (MessageEventAdded) will perform all - * the needed actions. - * - * this handler POSTs the event to the message window procedure - so it is fast and can exit quickly which will - * improve the overall responsiveness when receiving messages. - */ - -int CMimAPI::DispatchNewEvent(WPARAM hContact, LPARAM lParam) -{ - if (hContact) { - HWND h = M.FindWindow(hContact); - if (h == NULL) - h = M.FindWindow(hContact = db_event_getContact((HANDLE)lParam)); - if (h) - PostMessage(h, HM_DBEVENTADDED, hContact, lParam); // was SENDMESSAGE !!! XXX - } - return 0; -} - -/** - * Message event added is called when a new message is added to the database - * if no session is open for the contact, this function will determine if and how a new message - * session (tab) must be created. - * - * if a session is already created, it just does nothing and DispatchNewEvent() will take care. - */ - -int CMimAPI::MessageEventAdded(WPARAM hContact, LPARAM lParam) -{ - TCHAR szName[CONTAINER_NAMELEN + 1]; - - HANDLE hDbEvent = (HANDLE)lParam; - DBEVENTINFO dbei = { sizeof(dbei) }; - db_event_get(hDbEvent, &dbei); - - HWND hwnd = M.FindWindow(hContact); - if (hwnd == NULL) - hwnd = M.FindWindow(db_event_getContact(hDbEvent)); - - BOOL isCustomEvent = IsCustomEvent(dbei.eventType); - BOOL isShownCustomEvent = DbEventIsForMsgWindow(&dbei); - if (dbei.markedRead() || (isCustomEvent && !isShownCustomEvent)) - return 0; - - CallServiceSync(MS_CLIST_REMOVEEVENT, hContact, 1); - - bool bAllowAutoCreate = false; - bool bAutoPopup = M.GetByte(SRMSGSET_AUTOPOPUP, SRMSGDEFSET_AUTOPOPUP) != 0; - bool bAutoCreate = M.GetByte("autotabs", 1) != 0; - bool bAutoContainer = M.GetByte("autocontainer", 1) != 0; - DWORD dwStatusMask = M.GetDword("autopopupmask", -1); - - if (hwnd) { - TContainerData *pTargetContainer = 0; - SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pTargetContainer); - if (pTargetContainer == NULL || !PluginConfig.m_HideOnClose || IsWindowVisible(pTargetContainer->hwnd)) - return 0; - - WINDOWPLACEMENT wp = { 0 }; - wp.length = sizeof(wp); - GetWindowPlacement(pTargetContainer->hwnd, &wp); - GetContainerNameForContact(hContact, szName, CONTAINER_NAMELEN); - - if (bAutoPopup || bAutoCreate) { - if (bAutoPopup) { - if (wp.showCmd == SW_SHOWMAXIMIZED) - ShowWindow(pTargetContainer->hwnd, SW_SHOWMAXIMIZED); - else - ShowWindow(pTargetContainer->hwnd, SW_SHOWNOACTIVATE); - return 0; - } - - TContainerData *pContainer = FindContainerByName(szName); - if (pContainer != NULL) { - if (bAutoContainer) { - ShowWindow(pTargetContainer->hwnd, SW_SHOWMINNOACTIVE); - return 0; - } - goto nowindowcreate; - } - else if (bAutoContainer) { - ShowWindow(pTargetContainer->hwnd, SW_SHOWMINNOACTIVE); - return 0; - } - } - } - else { - switch (dbei.eventType) { - case EVENTTYPE_AUTHREQUEST: - case EVENTTYPE_ADDED: - return 0; - - case EVENTTYPE_FILE: - tabSRMM_ShowPopup(hContact, hDbEvent, dbei.eventType, 0, 0, 0, dbei.szModule, 0); - return 0; - } - } - - // if no window is open, we are not interested in anything else but unread message events - // new message - if (!nen_options.iNoSounds) - SkinPlaySound("AlertMsg"); - - if (nen_options.iNoAutoPopup) - goto nowindowcreate; - - GetContainerNameForContact(hContact, szName, CONTAINER_NAMELEN); - - if (dwStatusMask == -1) - bAllowAutoCreate = true; - else { - char *szProto = GetContactProto(hContact); - if (szProto && !strcmp(szProto, META_PROTO)) { - MCONTACT hSubconttact = (MCONTACT)CallService(MS_MC_GETMOSTONLINECONTACT, hContact, 0); - szProto = GetContactProto(hSubconttact); - } - if (szProto) { - DWORD dwStatus = (DWORD)CallProtoService(szProto, PS_GETSTATUS, 0, 0); - if (dwStatus == 0 || dwStatus <= ID_STATUS_OFFLINE || ((1 << (dwStatus - ID_STATUS_ONLINE)) & dwStatusMask)) // should never happen, but... - bAllowAutoCreate = true; - } - } - - if (bAllowAutoCreate && (bAutoPopup || bAutoCreate)) { - if (bAutoPopup) { - TContainerData *pContainer = FindContainerByName(szName); - if (pContainer == NULL) - pContainer = CreateContainer(szName, FALSE, hContact); - if (pContainer) - CreateNewTabForContact(pContainer, hContact, 0, NULL, TRUE, TRUE, FALSE, 0); - return 0; - } - - bool bActivate = false, bPopup = M.GetByte("cpopup", 0) != 0; - TContainerData *pContainer = FindContainerByName(szName); - if (pContainer != NULL) { - //if ((IsIconic(pContainer->hwnd)) && PluginConfig.haveAutoSwitch()) - // pContainer->dwFlags |= CNT_DEFERREDTABSELECT; - if (M.GetByte("limittabs", 0) && !wcsncmp(pContainer->szName, L"default", 6)) { - if ((pContainer = FindMatchingContainer(L"default", hContact)) != NULL) { - CreateNewTabForContact(pContainer, hContact, 0, NULL, bActivate, bPopup, TRUE, hDbEvent); - return 0; - } - } - else { - CreateNewTabForContact(pContainer, hContact, 0, NULL, bActivate, bPopup, TRUE, hDbEvent); - return 0; - } - } - if (bAutoContainer) { - if ((pContainer = CreateContainer(szName, CNT_CREATEFLAG_MINIMIZED, hContact)) != NULL) { // 2 means create minimized, don't popup... - CreateNewTabForContact(pContainer, hContact, 0, NULL, bActivate, bPopup, TRUE, hDbEvent); - SendMessageW(pContainer->hwnd, WM_SIZE, 0, 0); - } - return 0; - } - } - - /* - * for tray support, we add the event to the tray menu. otherwise we send it back to - * the contact list for flashing - */ -nowindowcreate: - if (!(dbei.flags & DBEF_READ)) { - UpdateTrayMenu(0, 0, dbei.szModule, NULL, hContact, 1); - if (!nen_options.bTraySupport) { - TCHAR toolTip[256], *contactName; - - CLISTEVENT cle = { sizeof(cle) }; - cle.hContact = hContact; - cle.hDbEvent = hDbEvent; - cle.flags = CLEF_TCHAR; - cle.hIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE); - cle.pszService = "SRMsg/ReadMessage"; - contactName = pcli->pfnGetContactDisplayName(hContact, 0); - mir_sntprintf(toolTip, SIZEOF(toolTip), TranslateT("Message from %s"), contactName); - cle.ptszTooltip = toolTip; - CallService(MS_CLIST_ADDEVENT, 0, (LPARAM)&cle); - } - tabSRMM_ShowPopup(hContact, hDbEvent, dbei.eventType, 0, 0, 0, dbei.szModule, 0); - } - return 0; -} - -CMimAPI M; -FI_INTERFACE *FIF = 0; +/* + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright (c) 2000-09 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. + * + * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors + * + * wraps some parts of Miranda API + * Also, OS dependent stuff (visual styles api etc.) + * + */ + +#include "commonheaders.h" + +PDTTE CMimAPI::m_pfnDrawThemeTextEx = 0; +DEFICA CMimAPI::m_pfnDwmExtendFrameIntoClientArea = 0; +DICE CMimAPI::m_pfnDwmIsCompositionEnabled = 0; +DRT CMimAPI::m_pfnDwmRegisterThumbnail = 0; +BPI CMimAPI::m_pfnBufferedPaintInit = 0; +BPU CMimAPI::m_pfnBufferedPaintUninit = 0; +BBP CMimAPI::m_pfnBeginBufferedPaint = 0; +EBP CMimAPI::m_pfnEndBufferedPaint = 0; +BBW CMimAPI::m_pfnDwmBlurBehindWindow = 0; +DGC CMimAPI::m_pfnDwmGetColorizationColor = 0; +BPSA CMimAPI::m_pfnBufferedPaintSetAlpha = 0; +DWMIIB CMimAPI::m_pfnDwmInvalidateIconicBitmaps = 0; +DWMSWA CMimAPI::m_pfnDwmSetWindowAttribute = 0; +DWMUT CMimAPI::m_pfnDwmUpdateThumbnailProperties = 0; +DURT CMimAPI::m_pfnDwmUnregisterThumbnail = 0; +DSIT CMimAPI::m_pfnDwmSetIconicThumbnail = 0; +DSILP CMimAPI::m_pfnDwmSetIconicLivePreviewBitmap = 0; +bool CMimAPI::m_shutDown = 0; +TCHAR CMimAPI::m_userDir[] = _T("\0"); + +bool CMimAPI::m_haveBufferedPaint = false; + +/** + * Case insensitive _tcsstr + * + * @param szString TCHAR *: String to be searched + * @param szSearchFor + *TCHAR *: String that should be found in szString + * + * @return TCHAR *: found position of szSearchFor in szString. 0 if szSearchFor was not found + */ +const TCHAR* CMimAPI::StriStr(const TCHAR *szString, const TCHAR *szSearchFor) +{ + assert(szString != 0 && szSearchFor != 0); + + if (!szString || *szString == 0) + return NULL; + + if (!szSearchFor || *szSearchFor == 0) + return szString; + + for (; *szString; ++szString) { + if (_totupper(*szString) == _totupper(*szSearchFor)) { + const TCHAR *h, *n; + for (h = szString, n = szSearchFor; *h && *n; ++h, ++n) + if (_totupper(*h) != _totupper(*n)) + break; + + if (!*n) + return szString; + } + } + return NULL; +} + +int CMimAPI::pathIsAbsolute(const TCHAR *path) const +{ + if (!path || !(lstrlen(path) > 2)) + return 0; + if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\')) + return 1; + return 0; +} + +size_t CMimAPI::pathToRelative(const TCHAR *pSrc, TCHAR *pOut, const TCHAR *szBase) const +{ + const TCHAR *tszBase = szBase ? szBase : m_szProfilePath; + + pOut[0] = 0; + if (!pSrc || !lstrlen(pSrc) || lstrlen(pSrc) > MAX_PATH) + return 0; + if (!pathIsAbsolute(pSrc)) { + mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc); + return lstrlen(pOut); + } + + TCHAR szTmp[MAX_PATH]; + mir_sntprintf(szTmp, SIZEOF(szTmp), _T("%s"), pSrc); + if (StriStr(szTmp, tszBase)) { + if (tszBase[lstrlen(tszBase) - 1] == '\\') + mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc + lstrlen(tszBase)); + else { + mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc + lstrlen(tszBase) + 1 ); + //pOut[0]='.'; + } + return(lstrlen(pOut)); + } + + mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc); + return(lstrlen(pOut)); +} + +/** + * Translate a relativ path to an absolute, using the current profile + * data directory. + * + * @param pSrc TCHAR *: input path + filename (relative) + * @param pOut TCHAR *: the result + * @param szBase TCHAR *: (OPTIONAL) base path for the translation. Can be 0 in which case + * the function will use m_szProfilePath (usually \tabSRMM below %miranda_userdata% + * + * @return + */ +size_t CMimAPI::pathToAbsolute(const TCHAR *pSrc, TCHAR *pOut, const TCHAR *szBase) const +{ + const TCHAR *tszBase = szBase ? szBase : m_szProfilePath; + + pOut[0] = 0; + if (!pSrc || !lstrlen(pSrc) || lstrlen(pSrc) > MAX_PATH) + return 0; + if (pathIsAbsolute(pSrc) && pSrc[0]!='.') + mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc); + else if (pSrc[0]=='.') + mir_sntprintf(pOut, MAX_PATH, _T("%s\\%s"), tszBase, pSrc + 1); + else + mir_sntprintf(pOut, MAX_PATH, _T("%s\\%s"), tszBase, pSrc); + + return lstrlen(pOut); +} + +/* + * window list functions + */ + +void CMimAPI::BroadcastMessage(UINT msg, WPARAM wParam, LPARAM lParam) +{ + WindowList_Broadcast(m_hMessageWindowList, msg, wParam, lParam); +} + +void CMimAPI::BroadcastMessageAsync(UINT msg, WPARAM wParam, LPARAM lParam) +{ + WindowList_BroadcastAsync(m_hMessageWindowList, msg, wParam, lParam); +} + +HWND CMimAPI::FindWindow(MCONTACT h) const +{ + return WindowList_Find(m_hMessageWindowList, h); +} + +INT_PTR CMimAPI::AddWindow(HWND hWnd, MCONTACT h) +{ + return WindowList_Add(m_hMessageWindowList, hWnd, h); +} + +INT_PTR CMimAPI::RemoveWindow(HWND hWnd) +{ + return WindowList_Remove(m_hMessageWindowList, hWnd); +} + +int CMimAPI::FoldersPathChanged(WPARAM wParam, LPARAM lParam) +{ + return M.foldersPathChanged(); +} + +void CMimAPI::configureCustomFolders() +{ + m_hDataPath = FoldersRegisterCustomPathT(LPGEN("TabSRMM"), LPGEN("Data path"), const_cast(getDataPath())); + m_hSkinsPath = FoldersRegisterCustomPathT(LPGEN("Skins"), LPGEN("TabSRMM"), const_cast(getSkinPath())); + m_hAvatarsPath = FoldersRegisterCustomPathT(LPGEN("Avatars"), LPGEN("Saved TabSRMM avatars"), const_cast(getSavedAvatarPath())); + m_hChatLogsPath = FoldersRegisterCustomPathT(LPGEN("TabSRMM"), LPGEN("Group chat logs root"), const_cast(getChatLogPath())); + + if (m_hDataPath) + HookEvent(ME_FOLDERS_PATH_CHANGED, CMimAPI::FoldersPathChanged); + + foldersPathChanged(); +} + +INT_PTR CMimAPI::foldersPathChanged() +{ + TCHAR szTemp[MAX_PATH + 2] = {'\0'}; + + if (m_hDataPath) { + FoldersGetCustomPathT(m_hDataPath, szTemp, MAX_PATH, const_cast(getDataPath())); + mir_sntprintf(m_szProfilePath, MAX_PATH, _T("%s"), szTemp); + + FoldersGetCustomPathT(m_hSkinsPath, szTemp, MAX_PATH, const_cast(getSkinPath())); + mir_sntprintf(m_szSkinsPath, MAX_PATH - 1, _T("%s"), szTemp); + Utils::ensureTralingBackslash(m_szSkinsPath); + + FoldersGetCustomPathT(m_hAvatarsPath, szTemp, MAX_PATH, const_cast(getSavedAvatarPath())); + mir_sntprintf(m_szSavedAvatarsPath, MAX_PATH, _T("%s"), szTemp); + + FoldersGetCustomPathT(m_hChatLogsPath, szTemp, MAX_PATH, const_cast(getChatLogPath())); + mir_sntprintf(m_szChatLogsPath, MAX_PATH, _T("%s"), szTemp); + Utils::ensureTralingBackslash(m_szChatLogsPath); + } + + CreateDirectoryTreeT(m_szProfilePath); + CreateDirectoryTreeT(m_szSkinsPath); + CreateDirectoryTreeT(m_szSavedAvatarsPath); + + Skin->extractSkinsAndLogo(true); + Skin->setupAeroSkins(); + return 0; +} + +const TCHAR* CMimAPI::getUserDir() +{ + if (m_userDir[0] == 0) { + if ( ServiceExists(MS_FOLDERS_REGISTER_PATH)) + lstrcpyn(m_userDir, L"%miranda_userdata%", SIZEOF(m_userDir)); + else + lstrcpyn(m_userDir, VARST( _T("%miranda_userdata%")), SIZEOF(m_userDir)); + + Utils::ensureTralingBackslash(m_userDir); + } + return m_userDir; +} + +void CMimAPI::InitPaths() +{ + m_szProfilePath[0] = 0; + m_szSkinsPath[0] = 0; + m_szSavedAvatarsPath[0] = 0; + + const TCHAR *szUserdataDir = getUserDir(); + + mir_sntprintf(m_szProfilePath, MAX_PATH, _T("%stabSRMM"), szUserdataDir); + if (ServiceExists(MS_FOLDERS_REGISTER_PATH)) { + lstrcpyn(m_szChatLogsPath, _T("%miranda_logpath%"), MAX_PATH); + lstrcpyn(m_szSkinsPath, _T("%miranda_path%\\Skins\\TabSRMM"), MAX_PATH); + } + else { + lstrcpyn(m_szChatLogsPath, VARST(_T("%miranda_logpath%")), MAX_PATH); + lstrcpyn(m_szSkinsPath, VARST(_T("%miranda_path%\\Skins\\TabSRMM")), MAX_PATH); + } + + Utils::ensureTralingBackslash(m_szChatLogsPath); + replaceStrT(g_Settings.pszLogDir, m_szChatLogsPath); + + Utils::ensureTralingBackslash(m_szSkinsPath); + + mir_sntprintf(m_szSavedAvatarsPath, MAX_PATH, _T("%s\\Saved Contact Pictures"), m_szProfilePath); +} + +bool CMimAPI::getAeroState() +{ + BOOL result = FALSE; + m_isAero = m_DwmActive = false; + if (IsWinVerVistaPlus()) { + m_DwmActive = (m_pfnDwmIsCompositionEnabled && (m_pfnDwmIsCompositionEnabled(&result) == S_OK) && result) ? true : false; + m_isAero = (CSkin::m_skinEnabled == false) && GetByte("useAero", 1) && CSkin::m_fAeroSkinsValid && m_DwmActive; + + } + m_isVsThemed = IsThemeActive() != 0; + return m_isAero; +} + +/** + * Initialize various Win32 API functions which are not common to all versions of Windows. + * We have to work with functions pointers here. + */ + +void CMimAPI::InitAPI() +{ + m_hUxTheme = 0; + + /* + * vista+ DWM API + */ + m_hDwmApi = 0; + if (IsWinVerVistaPlus()) { + m_hDwmApi = Utils::loadSystemLibrary(L"\\dwmapi.dll"); + if (m_hDwmApi) { + m_pfnDwmExtendFrameIntoClientArea = (DEFICA)GetProcAddress(m_hDwmApi,"DwmExtendFrameIntoClientArea"); + m_pfnDwmIsCompositionEnabled = (DICE)GetProcAddress(m_hDwmApi,"DwmIsCompositionEnabled"); + m_pfnDwmRegisterThumbnail = (DRT)GetProcAddress(m_hDwmApi, "DwmRegisterThumbnail"); + m_pfnDwmBlurBehindWindow = (BBW)GetProcAddress(m_hDwmApi, "DwmEnableBlurBehindWindow"); + m_pfnDwmGetColorizationColor = (DGC)GetProcAddress(m_hDwmApi, "DwmGetColorizationColor"); + m_pfnDwmInvalidateIconicBitmaps = (DWMIIB)GetProcAddress(m_hDwmApi, "DwmInvalidateIconicBitmaps"); + m_pfnDwmSetWindowAttribute = (DWMSWA)GetProcAddress(m_hDwmApi, "DwmSetWindowAttribute"); + m_pfnDwmUpdateThumbnailProperties = (DWMUT)GetProcAddress(m_hDwmApi, "DwmUpdateThumbnailProperties"); + m_pfnDwmUnregisterThumbnail = (DURT)GetProcAddress(m_hDwmApi, "DwmUnregisterThumbnail"); + m_pfnDwmSetIconicThumbnail = (DSIT)GetProcAddress(m_hDwmApi, "DwmSetIconicThumbnail"); + m_pfnDwmSetIconicLivePreviewBitmap = (DSILP)GetProcAddress(m_hDwmApi, "DwmSetIconicLivePreviewBitmap"); + } + /* + * additional uxtheme APIs (Vista+) + */ + m_hUxTheme = Utils::loadSystemLibrary(L"\\uxtheme.dll"); + if (m_hUxTheme) { + m_pfnDrawThemeTextEx = (PDTTE)GetProcAddress(m_hUxTheme, "DrawThemeTextEx"); + m_pfnBeginBufferedPaint = (BBP)GetProcAddress(m_hUxTheme, "BeginBufferedPaint"); + m_pfnEndBufferedPaint = (EBP)GetProcAddress(m_hUxTheme, "EndBufferedPaint"); + m_pfnBufferedPaintInit = (BPI)GetProcAddress(m_hUxTheme, "BufferedPaintInit"); + m_pfnBufferedPaintUninit = (BPU)GetProcAddress(m_hUxTheme, "BufferedPaintUnInit"); + m_pfnBufferedPaintSetAlpha = (BPSA)GetProcAddress(m_hUxTheme, "BufferedPaintSetAlpha"); + m_haveBufferedPaint = (m_pfnBeginBufferedPaint != 0 && m_pfnEndBufferedPaint != 0) ? true : false; + if (m_haveBufferedPaint) + m_pfnBufferedPaintInit(); + } + } + else m_haveBufferedPaint = false; +} + +/** + * hook subscriber function for incoming message typing events + */ + +int CMimAPI::TypingMessage(WPARAM hContact, LPARAM lParam) +{ + HWND hwnd = 0; + int issplit = 1, foundWin = 0, preTyping = 0; + BOOL fShowOnClist = TRUE; + + if (hContact) { + if ((hwnd = M.FindWindow(hContact)) && M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPING, SRMSGDEFSET_SHOWTYPING)) + preTyping = SendMessage(hwnd, DM_TYPING, 0, lParam); + + if (hwnd && IsWindowVisible(hwnd)) + foundWin = MessageWindowOpened(0, (LPARAM)hwnd); + else + foundWin = 0; + + TContainerData *pContainer = NULL; + if (hwnd) { + SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pContainer); + if (pContainer == NULL) + return 0; // should never happen + } + + if ( M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGCLIST, SRMSGDEFSET_SHOWTYPINGCLIST)) { + if (!hwnd && !M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGNOWINOPEN, 1)) + fShowOnClist = FALSE; + if (hwnd && !M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGWINOPEN, 1)) + fShowOnClist = FALSE; + } + else fShowOnClist = FALSE; + + if ((!foundWin || !(pContainer->dwFlags & CNT_NOSOUND)) && preTyping != (lParam != 0)) + SkinPlaySound((lParam) ? "TNStart" : "TNStop"); + + if (M.GetByte(SRMSGMOD, "ShowTypingPopup", 0)) { + BOOL fShow = FALSE; + int iMode = M.GetByte("MTN_PopupMode", 0); + + switch(iMode) { + case 0: + fShow = TRUE; + break; + case 1: + if (!foundWin || !(pContainer && pContainer->hwndActive == hwnd && GetForegroundWindow() == pContainer->hwnd)) + fShow = TRUE; + break; + case 2: + if (hwnd == 0) + fShow = TRUE; + else { + if (PluginConfig.m_HideOnClose) { + TContainerData *pContainer = 0; + SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pContainer); + if (pContainer && pContainer->fHidden) + fShow = TRUE; + } + } + break; + } + if (fShow) + TN_TypingMessage(hContact, lParam); + } + + if (lParam) { + TCHAR szTip[256]; + mir_sntprintf(szTip, SIZEOF(szTip), TranslateT("%s is typing a message"), pcli->pfnGetContactDisplayName(hContact, 0)); + if (fShowOnClist && ServiceExists(MS_CLIST_SYSTRAY_NOTIFY) && M.GetByte(SRMSGMOD, "ShowTypingBalloon", 0)) { + MIRANDASYSTRAYNOTIFY tn; + tn.szProto = NULL; + tn.cbSize = sizeof(tn); + tn.tszInfoTitle = TranslateT("Typing Notification"); + tn.tszInfo = szTip; + tn.dwInfoFlags = NIIF_INFO | NIIF_INTERN_UNICODE; + tn.uTimeout = 1000 * 4; + CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM)&tn); + } + if (fShowOnClist) { + CLISTEVENT cle = { sizeof(cle) }; + cle.hContact = hContact; + cle.hDbEvent = (HANDLE)1; + cle.flags = CLEF_ONLYAFEW | CLEF_TCHAR; + cle.hIcon = PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]; + cle.pszService = "SRMsg/TypingMessage"; + cle.ptszTooltip = szTip; + CallServiceSync(MS_CLIST_REMOVEEVENT, hContact, 1); + CallServiceSync(MS_CLIST_ADDEVENT, hContact, (LPARAM)&cle); + } + } + } + return 0; +} + +/** + * this is the global ack dispatcher. It handles both ACKTYPE_MESSAGE and ACKTYPE_AVATAR events + * for ACKTYPE_MESSAGE it searches the corresponding send job in the queue and, if found, dispatches + * it to the owners window + * + * ACKTYPE_AVATAR no longer handled here, because we have avs services now. + */ + +int CMimAPI::ProtoAck(WPARAM wParam, LPARAM lParam) +{ + ACKDATA *pAck = (ACKDATA*)lParam; + if (lParam == 0) + return 0; + + HWND hwndDlg = 0; + int i=0, iFound = SendQueue::NR_SENDJOBS; + SendJob *jobs = sendQueue->getJobByIndex(0); + + if (pAck->type == ACKTYPE_MESSAGE) { + MCONTACT hMeta = db_mc_getMeta(pAck->hContact); + for (int j = 0; j < SendQueue::NR_SENDJOBS; j++) { + SendJob &p = jobs[j]; + if (pAck->hProcess == p.hSendId && pAck->hContact == p.hOwner) { + TWindowData *dat = p.hwndOwner ? (TWindowData*)GetWindowLongPtr(p.hwndOwner, GWLP_USERDATA) : NULL; + if (dat == NULL) { + sendQueue->ackMessage(NULL, (WPARAM)MAKELONG(j, i), lParam); + return 0; + } + if (dat->hContact == p.hOwner || dat->hContact == hMeta) { + iFound = j; + break; + } + } + if (iFound != SendQueue::NR_SENDJOBS) // no mathing entry found in this queue entry.. continue + break; + } + if (iFound == SendQueue::NR_SENDJOBS) // no matching send info found in the queue + sendLater->processAck(pAck); + else // try to find the process handle in the list of open send later jobs + SendMessage(jobs[iFound].hwndOwner, HM_EVENTSENT, (WPARAM)MAKELONG(iFound, i), lParam); + } + return 0; +} + +int CMimAPI::PrebuildContactMenu(WPARAM hContact, LPARAM lParam) +{ + if (hContact == NULL) + return NULL; + + bool bEnabled = false; + char *szProto = GetContactProto(hContact); + if (szProto) { + // leave this menu item hidden for chats + if ( !db_get_b(hContact, szProto, "ChatRoom", 0 )) + if ( CallProtoService( szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IMSEND) + bEnabled = true; + } + + Menu_ShowItem(PluginConfig.m_hMenuItem, bEnabled); + return 0; +} + +/** + * this handler is called first in the message window chain - it will handle events for which a message window + * is already open. if not, it will do nothing and the 2nd handler (MessageEventAdded) will perform all + * the needed actions. + * + * this handler POSTs the event to the message window procedure - so it is fast and can exit quickly which will + * improve the overall responsiveness when receiving messages. + */ + +int CMimAPI::DispatchNewEvent(WPARAM hContact, LPARAM lParam) +{ + if (hContact) { + HWND h = M.FindWindow(hContact); + if (h == NULL) + h = M.FindWindow(hContact = db_event_getContact((HANDLE)lParam)); + if (h) + PostMessage(h, HM_DBEVENTADDED, hContact, lParam); // was SENDMESSAGE !!! XXX + } + return 0; +} + +/** + * Message event added is called when a new message is added to the database + * if no session is open for the contact, this function will determine if and how a new message + * session (tab) must be created. + * + * if a session is already created, it just does nothing and DispatchNewEvent() will take care. + */ + +int CMimAPI::MessageEventAdded(WPARAM hContact, LPARAM lParam) +{ + TCHAR szName[CONTAINER_NAMELEN + 1]; + + HANDLE hDbEvent = (HANDLE)lParam; + DBEVENTINFO dbei = { sizeof(dbei) }; + db_event_get(hDbEvent, &dbei); + + HWND hwnd = M.FindWindow(hContact); + if (hwnd == NULL) + hwnd = M.FindWindow(db_event_getContact(hDbEvent)); + + BOOL isCustomEvent = IsCustomEvent(dbei.eventType); + BOOL isShownCustomEvent = DbEventIsForMsgWindow(&dbei); + if (dbei.markedRead() || (isCustomEvent && !isShownCustomEvent)) + return 0; + + CallServiceSync(MS_CLIST_REMOVEEVENT, hContact, 1); + + bool bAllowAutoCreate = false; + bool bAutoPopup = M.GetByte(SRMSGSET_AUTOPOPUP, SRMSGDEFSET_AUTOPOPUP) != 0; + bool bAutoCreate = M.GetByte("autotabs", 1) != 0; + bool bAutoContainer = M.GetByte("autocontainer", 1) != 0; + DWORD dwStatusMask = M.GetDword("autopopupmask", -1); + + if (hwnd) { + TContainerData *pTargetContainer = 0; + SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pTargetContainer); + if (pTargetContainer == NULL || !PluginConfig.m_HideOnClose || IsWindowVisible(pTargetContainer->hwnd)) + return 0; + + WINDOWPLACEMENT wp = { 0 }; + wp.length = sizeof(wp); + GetWindowPlacement(pTargetContainer->hwnd, &wp); + GetContainerNameForContact(hContact, szName, CONTAINER_NAMELEN); + + if (bAutoPopup || bAutoCreate) { + if (bAutoPopup) { + if (wp.showCmd == SW_SHOWMAXIMIZED) + ShowWindow(pTargetContainer->hwnd, SW_SHOWMAXIMIZED); + else + ShowWindow(pTargetContainer->hwnd, SW_SHOWNOACTIVATE); + return 0; + } + + TContainerData *pContainer = FindContainerByName(szName); + if (pContainer != NULL) { + if (bAutoContainer) { + ShowWindow(pTargetContainer->hwnd, SW_SHOWMINNOACTIVE); + return 0; + } + goto nowindowcreate; + } + else if (bAutoContainer) { + ShowWindow(pTargetContainer->hwnd, SW_SHOWMINNOACTIVE); + return 0; + } + } + } + else { + switch (dbei.eventType) { + case EVENTTYPE_AUTHREQUEST: + case EVENTTYPE_ADDED: + return 0; + + case EVENTTYPE_FILE: + tabSRMM_ShowPopup(hContact, hDbEvent, dbei.eventType, 0, 0, 0, dbei.szModule, 0); + return 0; + } + } + + // if no window is open, we are not interested in anything else but unread message events + // new message + if (!nen_options.iNoSounds) + SkinPlaySound("AlertMsg"); + + if (nen_options.iNoAutoPopup) + goto nowindowcreate; + + GetContainerNameForContact(hContact, szName, CONTAINER_NAMELEN); + + if (dwStatusMask == -1) + bAllowAutoCreate = true; + else { + char *szProto = GetContactProto(hContact); + if (szProto && !strcmp(szProto, META_PROTO)) { + MCONTACT hSubconttact = (MCONTACT)CallService(MS_MC_GETMOSTONLINECONTACT, hContact, 0); + szProto = GetContactProto(hSubconttact); + } + if (szProto) { + DWORD dwStatus = (DWORD)CallProtoService(szProto, PS_GETSTATUS, 0, 0); + if (dwStatus == 0 || dwStatus <= ID_STATUS_OFFLINE || ((1 << (dwStatus - ID_STATUS_ONLINE)) & dwStatusMask)) // should never happen, but... + bAllowAutoCreate = true; + } + } + + if (bAllowAutoCreate && (bAutoPopup || bAutoCreate)) { + if (bAutoPopup) { + TContainerData *pContainer = FindContainerByName(szName); + if (pContainer == NULL) + pContainer = CreateContainer(szName, FALSE, hContact); + if (pContainer) + CreateNewTabForContact(pContainer, hContact, 0, NULL, TRUE, TRUE, FALSE, 0); + return 0; + } + + bool bActivate = false, bPopup = M.GetByte("cpopup", 0) != 0; + TContainerData *pContainer = FindContainerByName(szName); + if (pContainer != NULL) { + //if ((IsIconic(pContainer->hwnd)) && PluginConfig.haveAutoSwitch()) + // pContainer->dwFlags |= CNT_DEFERREDTABSELECT; + if (M.GetByte("limittabs", 0) && !wcsncmp(pContainer->szName, L"default", 6)) { + if ((pContainer = FindMatchingContainer(L"default", hContact)) != NULL) { + CreateNewTabForContact(pContainer, hContact, 0, NULL, bActivate, bPopup, TRUE, hDbEvent); + return 0; + } + } + else { + CreateNewTabForContact(pContainer, hContact, 0, NULL, bActivate, bPopup, TRUE, hDbEvent); + return 0; + } + } + if (bAutoContainer) { + if ((pContainer = CreateContainer(szName, CNT_CREATEFLAG_MINIMIZED, hContact)) != NULL) { // 2 means create minimized, don't popup... + CreateNewTabForContact(pContainer, hContact, 0, NULL, bActivate, bPopup, TRUE, hDbEvent); + SendMessageW(pContainer->hwnd, WM_SIZE, 0, 0); + } + return 0; + } + } + + /* + * for tray support, we add the event to the tray menu. otherwise we send it back to + * the contact list for flashing + */ +nowindowcreate: + if (!(dbei.flags & DBEF_READ)) { + UpdateTrayMenu(0, 0, dbei.szModule, NULL, hContact, 1); + if (!nen_options.bTraySupport) { + TCHAR toolTip[256], *contactName; + + CLISTEVENT cle = { sizeof(cle) }; + cle.hContact = hContact; + cle.hDbEvent = hDbEvent; + cle.flags = CLEF_TCHAR; + cle.hIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE); + cle.pszService = "SRMsg/ReadMessage"; + contactName = pcli->pfnGetContactDisplayName(hContact, 0); + mir_sntprintf(toolTip, SIZEOF(toolTip), TranslateT("Message from %s"), contactName); + cle.ptszTooltip = toolTip; + CallService(MS_CLIST_ADDEVENT, 0, (LPARAM)&cle); + } + tabSRMM_ShowPopup(hContact, hDbEvent, dbei.eventType, 0, 0, 0, dbei.szModule, 0); + } + return 0; +} + +CMimAPI M; +FI_INTERFACE *FIF = 0; -- cgit v1.2.3