From f920ef497f3299ae24fe783ce03bdd93b419f764 Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Fri, 18 May 2012 22:02:50 +0000 Subject: plugins folders renaming git-svn-id: http://svn.miranda-ng.org/main/trunk@60 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/SmileyAdd/dlgboxsubclass.cpp | 568 +++++++++++++++++++++++++++++++++++ 1 file changed, 568 insertions(+) create mode 100644 plugins/SmileyAdd/dlgboxsubclass.cpp (limited to 'plugins/SmileyAdd/dlgboxsubclass.cpp') diff --git a/plugins/SmileyAdd/dlgboxsubclass.cpp b/plugins/SmileyAdd/dlgboxsubclass.cpp new file mode 100644 index 0000000000..8da22c6cb1 --- /dev/null +++ b/plugins/SmileyAdd/dlgboxsubclass.cpp @@ -0,0 +1,568 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2005 - 2011 Boris Krasnovskiy All Rights Reserved +Copyright (C) 2003 - 2004 Rein-Peter de Boer + +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 version 2 +of the License. + +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, see . +*/ + +#include "general.h" +#include "smileyroutines.h" +#include "services.h" +#include "options.h" + +//***************************************************// +// DISCLAIMER!!! +// we are not supposed to use this object, so be aware +typedef struct NewMessageWindowLParam +{ + HANDLE hContact; + int isSend; + const char *szInitialText; +} +msgData; +// this is an undocumented object!!!!!!! +// subject to change in miranda versions...!!!!!! +// DISCLAIMER!!! +//***************************************************// + +extern HINSTANCE g_hInst; + +static HHOOK g_hMessageHookPre = NULL; +static HANDLE g_hMutex = NULL; +static HANDLE g_hHookMsgWnd = NULL; + +static LRESULT CALLBACK MessageDlgSubclas(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + + +//type definitions +class MsgWndData +{ +public: + HWND hwnd; + char ProtocolName[52]; + HWND REdit; + HWND QuoteB; + HWND MEdit; + HWND MOK; + HWND LButton; + mutable HWND hSmlButton; + mutable HBITMAP hSmlBmp; + mutable HICON hSmlIco; + int idxLastChar; + WNDPROC wpOrigWndProc; + HANDLE hContact; + bool doSmileyReplace; + bool doSmileyButton; + bool OldButtonPlace; + bool isSplit; + bool isSend; + + MsgWndData() + { + ProtocolName[0] = 0; + REdit = NULL; + QuoteB = NULL; + MEdit = NULL; + MOK = NULL; + LButton = NULL; + hSmlButton = NULL; + hSmlBmp = NULL; + hSmlIco = NULL; + idxLastChar = 0; + hContact = NULL; + doSmileyReplace = false; + doSmileyButton = false; + OldButtonPlace = false; + isSplit = false; + isSend = false; + wpOrigWndProc = NULL; + } + + MsgWndData(const MsgWndData &dsb) + { + *this = dsb; + dsb.hSmlBmp = NULL; + dsb.hSmlIco = NULL; + dsb.hSmlButton = NULL; + } + + + ~MsgWndData() + { + clear(); + } + + void clear(void) + { + if (hSmlBmp != NULL) DeleteObject(hSmlBmp); + if (hSmlIco != NULL) DestroyIcon(hSmlIco); + if (hSmlButton != NULL) DestroyWindow(hSmlButton); + hSmlBmp = NULL; + hSmlIco = NULL; + hSmlButton = NULL; + } + + RECT CalcSmileyButtonPos(void) + { + RECT rect; + POINT pt; + + if (OldButtonPlace) + { + if (isSplit && DBGetContactSettingByte(NULL, "SRMsg", "ShowQuote", FALSE)) + { + GetWindowRect(QuoteB, &rect); + pt.x = rect.right + 12; + } + else + { + GetWindowRect(MEdit, &rect); + pt.x = rect.left; + } + GetWindowRect(MOK, &rect); + pt.y = rect.top; + } + else + { + GetWindowRect(LButton, &rect); + pt.y = rect.top; + + if ((GetWindowLong(LButton, GWL_STYLE) & WS_VISIBLE) != 0) + pt.x = rect.left - 28; + else + pt.x = rect.left; + } + + ScreenToClient(GetParent(LButton), &pt); + rect.bottom += pt.y - rect.top; + rect.right += pt.x - rect.left; + rect.top = pt.y; + rect.left = pt.x; + + return rect; + } + + //helper function + //identifies the message dialog + bool IsMessageSendDialog(HWND hwnd) + { + TCHAR szClassName[32] = _T(""); + + GetClassName(hwnd, szClassName, SIZEOF(szClassName)); + if (_tcscmp(szClassName, _T("#32770"))) return false; + + if ((REdit = GetDlgItem(hwnd, MI_IDC_LOG)) != NULL) + { + GetClassName(REdit, szClassName, SIZEOF(szClassName)); + if (_tcscmp(szClassName, _T("RichEdit20A")) != 0 && + _tcscmp(szClassName, _T("RichEdit20W")) != 0 && + _tcscmp(szClassName, _T("RICHEDIT50W")) != 0) return false; + } + else return false; + + if ((MEdit = GetDlgItem(hwnd, MI_IDC_MESSAGE)) != NULL) + { + GetClassName(MEdit, szClassName, SIZEOF(szClassName)); + if (_tcscmp(szClassName, _T("Edit")) != 0 && + _tcscmp(szClassName, _T("RichEdit20A")) != 0 && + _tcscmp(szClassName, _T("RichEdit20W")) != 0 && + _tcscmp(szClassName, _T("RICHEDIT50W")) != 0) return false; + } + else return false; + + QuoteB = GetDlgItem(hwnd, MI_IDC_QUOTE); + + if ((LButton = GetDlgItem(hwnd, MI_IDC_ADD)) == NULL) + return false; + + if (GetDlgItem(hwnd, MI_IDC_NAME) == NULL) + return false; + if ((MOK = GetDlgItem(hwnd, IDOK)) == NULL) + return false; + + return true; + } + + void CreateSmileyButton(void) + { + doSmileyButton = opt.ButtonStatus != 0; + OldButtonPlace = opt.ButtonStatus == 2; + + SmileyPackType* SmileyPack = GetSmileyPack(ProtocolName, hContact); + doSmileyButton &= SmileyPack != NULL && SmileyPack->VisibleSmileyCount() != 0; + + bool showButtonLine; + if (IsOldSrmm()) + { + isSplit = DBGetContactSettingByte(NULL,"SRMsg","Split", TRUE) != 0; + + doSmileyReplace = (isSplit || !isSend); + doSmileyButton &= isSplit || isSend; + showButtonLine = DBGetContactSettingByte(NULL, "SRMsg", "ShowButtonLine", TRUE) != 0; + } + else + { + doSmileyReplace = true;; + OldButtonPlace = false; + showButtonLine = DBGetContactSettingByte(NULL, "SRMM", "ShowButtonLine", TRUE) != 0; + } + + doSmileyButton &= OldButtonPlace || showButtonLine; + + if (ProtocolName[0] != 0) + { + INT_PTR cap = CallProtoService(ProtocolName, PS_GETCAPS, PFLAGNUM_1, 0); + doSmileyButton &= ((cap & PF1_IMSEND) != 0); + doSmileyReplace &= ((cap & PF1_IMRECV) != 0); + } + + if (doSmileyButton && opt.PluginSupportEnabled) + { + //create smiley button + RECT rect = CalcSmileyButtonPos(); + + hSmlButton = CreateWindowEx( + WS_EX_LEFT | WS_EX_NOPARENTNOTIFY | WS_EX_TOPMOST, + MIRANDABUTTONCLASS, + _T("S"), + WS_CHILD|WS_VISIBLE|WS_TABSTOP, // window style + rect.left, // horizontal position of window + rect.top, // vertical position of window + rect.bottom - rect.top + 1, // window width + rect.bottom - rect.top + 1, // window height + GetParent(LButton), // handle to parent or owner window + (HMENU) IDC_SMLBUTTON, // menu handle or child identifier + NULL, // handle to application instance + NULL); // window-creation data + + // Conversion to bitmap done to prevent Miranda from scaling the image + SmileyType* sml = FindButtonSmiley(SmileyPack); + if (sml != NULL) + { + hSmlBmp = sml->GetBitmap(GetSysColor(COLOR_BTNFACE), 0, 0); + SendMessage(hSmlButton, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hSmlBmp); + } + else + { + hSmlIco = GetDefaultIcon(); + SendMessage(hSmlButton, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hSmlIco); + } + + SendMessage(hSmlButton, BUTTONADDTOOLTIP, (WPARAM)LPGEN("Show Smiley Selection Window"), 0); + SendMessage(hSmlButton, BUTTONSETASFLATBTN, 0, 0); + } + } +}; + +static int CompareMsgWndData(const MsgWndData* p1, const MsgWndData* p2) +{ + return (int)((INT_PTR)p1->hwnd - (INT_PTR)p2->hwnd); +} +static LIST g_MsgWndList(10, CompareMsgWndData); + + +bool IsOldSrmm(void) +{ + return ServiceExists(MS_MSG_GETWINDOWCLASS) == 0; +} + + +int UpdateSrmmDlg(WPARAM wParam, LPARAM /* lParam */) +{ + WaitForSingleObject(g_hMutex, 2000); + for (int i=0; ihContact == (HANDLE)wParam) + { + SendMessage(g_MsgWndList[i]->hwnd, WM_SETREDRAW, FALSE, 0); + SendMessage(g_MsgWndList[i]->hwnd, DM_OPTIONSAPPLIED, 0, 0); + SendMessage(g_MsgWndList[i]->hwnd, WM_SETREDRAW, TRUE, 0); + } + } + ReleaseMutex(g_hMutex); + + return 0; +} + + +//find the dialog info in the stored list +static MsgWndData* IsMsgWnd(HWND hwnd) +{ + WaitForSingleObject(g_hMutex, 2000); + MsgWndData* res = g_MsgWndList.find((MsgWndData*)&hwnd); + ReleaseMutex(g_hMutex); + + return res; +} + + +static void MsgWndDetect(HWND hwndDlg, HANDLE hContact, msgData* datm) +{ + MsgWndData dat; + + if (dat.IsMessageSendDialog(hwndDlg)) + { + dat.hwnd = hwndDlg; + if (datm != NULL) + { + dat.isSend = datm->isSend != 0; + dat.hContact = datm->hContact; + } + else + dat.hContact = hContact; + + // Get the protocol for this contact to display correct smileys. + char *protonam = (char*) CallService(MS_PROTO_GETCONTACTBASEPROTO, + (WPARAM)DecodeMetaContact(dat.hContact), 0); + + if (protonam) + { + strncpy(dat.ProtocolName, protonam, sizeof(dat.ProtocolName)); + dat.ProtocolName[sizeof(dat.ProtocolName)-1] = 0; + } + + WaitForSingleObject(g_hMutex, 2000); + + MsgWndData* msgwnd = g_MsgWndList.find((MsgWndData*)&hwndDlg); + if (msgwnd == NULL) + { + msgwnd = new MsgWndData(dat); + g_MsgWndList.insert(msgwnd); + } + else + msgwnd = NULL; + ReleaseMutex(g_hMutex); + + if (msgwnd != NULL) + { + msgwnd->wpOrigWndProc = (WNDPROC)SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)MessageDlgSubclas); + msgwnd->CreateSmileyButton(); + if (hContact == NULL) SetRichCallback(msgwnd->REdit, msgwnd->hContact, true, true); + } + } +} + + +//global subclass function for all dialogs +static LRESULT CALLBACK MessageDlgSubclas(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + MsgWndData* dat = IsMsgWnd(hwnd); + if (dat == NULL) return 0; + + switch(uMsg) + { + case DM_OPTIONSAPPLIED: + dat->clear(); + dat->CreateSmileyButton(); + break; + + case DM_APPENDTOLOG: + if (opt.PluginSupportEnabled) + { + //get length of text now before things can get added... + GETTEXTLENGTHEX gtl; + gtl.codepage = 1200; + gtl.flags = GTL_PRECISE | GTL_NUMCHARS; + dat->idxLastChar = (int)SendMessage(dat->REdit, EM_GETTEXTLENGTHEX, (WPARAM) >l, 0); + } + break; + } + + LRESULT result = CallWindowProc(dat->wpOrigWndProc, hwnd, uMsg, wParam, lParam); + + if (!opt.PluginSupportEnabled) return result; + + switch(uMsg) + { + case WM_DESTROY: + WaitForSingleObject(g_hMutex, 2000); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)dat->wpOrigWndProc); + { + int ind = g_MsgWndList.getIndex((MsgWndData*)&hwnd); + if ( ind != -1 ) + { + delete g_MsgWndList[ind]; + g_MsgWndList.remove(ind); + } + } + ReleaseMutex(g_hMutex); + break; + + case WM_SIZE: + if (dat->doSmileyButton) + { + RECT rect = dat->CalcSmileyButtonPos(); + SetWindowPos(dat->hSmlButton, NULL, rect.left, rect.top, + 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); + } + break; + + case DM_APPENDTOLOG: + if (dat->doSmileyReplace) + { + SmileyPackCType* smcp; + SmileyPackType* SmileyPack = GetSmileyPack(dat->ProtocolName, dat->hContact, &smcp); + if (SmileyPack != NULL) + { + const CHARRANGE sel = { dat->idxLastChar, LONG_MAX }; + ReplaceSmileys(dat->REdit, SmileyPack, smcp, sel, false, false, false); + } + } + break; + + case DM_REMAKELOG: + if (dat->doSmileyReplace) + { + SmileyPackCType* smcp; + SmileyPackType* SmileyPack = GetSmileyPack(dat->ProtocolName, dat->hContact, &smcp); + if (SmileyPack != NULL) + { + static const CHARRANGE sel = { 0, LONG_MAX }; + ReplaceSmileys(dat->REdit, SmileyPack, smcp, sel, false, false, false); + } + } + break; + + case WM_COMMAND: + if (LOWORD(wParam) == IDC_SMLBUTTON && + HIWORD(wParam) == BN_CLICKED) + { + SmileyToolWindowParam *stwp = new SmileyToolWindowParam; + stwp->pSmileyPack = GetSmileyPack(dat->ProtocolName, dat->hContact); + + stwp->hWndParent = hwnd; + stwp->hWndTarget = dat->MEdit; + stwp->targetMessage = EM_REPLACESEL; + stwp->targetWParam = TRUE; + + RECT rect; + GetWindowRect(dat->hSmlButton, &rect); + + if (dat->OldButtonPlace) + { + stwp->direction = 3; + stwp->xPosition = rect.left; + stwp->yPosition = rect.top + 4; + } + else + { + stwp->direction = 0; + stwp->xPosition = rect.left; + stwp->yPosition = rect.top + 24; + } + + mir_forkthread(SmileyToolThread, stwp); + } + + if (LOWORD(wParam) == MI_IDC_ADD && + HIWORD(wParam) == BN_CLICKED && + dat->doSmileyButton) + { + RECT rect = dat->CalcSmileyButtonPos(); + SetWindowPos(dat->hSmlButton, NULL, rect.left, rect.top, + 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); + } + break; + } + + return result; +} + +static int MsgDlgHook(WPARAM, LPARAM lParam) +{ + const MessageWindowEventData *wndEvtData = (MessageWindowEventData*)lParam; + switch(wndEvtData->uType) + { + case MSG_WINDOW_EVT_OPENING: + MsgWndDetect(wndEvtData->hwndWindow, wndEvtData->hContact, NULL); + if (wndEvtData->cbSize >= sizeof(MessageWindowEventData)) + { + SetRichOwnerCallback(wndEvtData->hwndWindow, wndEvtData->hwndInput, wndEvtData->hwndLog); + + if (wndEvtData->hwndLog) + SetRichCallback(wndEvtData->hwndLog, wndEvtData->hContact, false, false); + if (wndEvtData->hwndInput) + SetRichCallback(wndEvtData->hwndInput, wndEvtData->hContact, false, false); + } + break; + + case MSG_WINDOW_EVT_OPEN: + if (wndEvtData->cbSize >= sizeof(MessageWindowEventData)) + { + SetRichOwnerCallback(wndEvtData->hwndWindow, wndEvtData->hwndInput, wndEvtData->hwndLog); + if (wndEvtData->hwndLog) + SetRichCallback(wndEvtData->hwndLog, wndEvtData->hContact, true, true); + if (wndEvtData->hwndInput) + { + SetRichCallback(wndEvtData->hwndInput, wndEvtData->hContact, true, true); + SendMessage(wndEvtData->hwndInput, WM_REMAKERICH, 0, 0); + } + } + break; + + case MSG_WINDOW_EVT_CLOSE: + if (wndEvtData->cbSize >= sizeof(MessageWindowEventData) && wndEvtData->hwndLog) + { + CloseRichCallback(wndEvtData->hwndLog, true); + CloseRichOwnerCallback(wndEvtData->hwndWindow, true); + } + break; + } + return 0; +} + + +//global subclass function for all dialogs +static LRESULT CALLBACK MsgDlgHookProcPre(int code, WPARAM wParam, LPARAM lParam) +{ + const CWPSTRUCT *msg = (CWPSTRUCT*)lParam; + + if (code == HC_ACTION && msg->message == WM_INITDIALOG) + MsgWndDetect(msg->hwnd, NULL, (msgData*)msg->lParam); + + return CallNextHookEx(g_hMessageHookPre, code, wParam, lParam); +} + + +void InstallDialogBoxHook(void) +{ + g_hMutex = CreateMutex(NULL, FALSE, NULL); + + g_hHookMsgWnd = HookEvent(ME_MSG_WINDOWEVENT, MsgDlgHook); + + // Hook message API + if (g_hHookMsgWnd == NULL) + g_hMessageHookPre = SetWindowsHookEx(WH_CALLWNDPROC, MsgDlgHookProcPre, + NULL, GetCurrentThreadId()); +} + + +void RemoveDialogBoxHook(void) +{ + if (g_hHookMsgWnd) UnhookEvent(g_hHookMsgWnd); + if (g_hMessageHookPre) UnhookWindowsHookEx(g_hMessageHookPre); + + WaitForSingleObject(g_hMutex, 2000); + for (int i=0; i