summaryrefslogtreecommitdiff
path: root/plugins/SmileyAdd/dlgboxsubclass.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/SmileyAdd/dlgboxsubclass.cpp')
-rw-r--r--plugins/SmileyAdd/dlgboxsubclass.cpp568
1 files changed, 568 insertions, 0 deletions
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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<MsgWndData> 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; i<g_MsgWndList.getCount(); ++i)
+ {
+ if (wParam == 0 || g_MsgWndList[i]->hContact == (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) &gtl, 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<g_MsgWndList.getCount(); ++i)
+ delete g_MsgWndList[i];
+ g_MsgWndList.destroy();
+ ReleaseMutex(g_hMutex);
+
+ if (g_hMutex) CloseHandle(g_hMutex);
+
+ g_hHookMsgWnd = NULL;
+ g_hMessageHookPre = NULL;
+ g_hMutex = NULL;
+}