diff options
author | Vadim Dashevskiy <watcherhd@gmail.com> | 2012-05-15 10:38:20 +0000 |
---|---|---|
committer | Vadim Dashevskiy <watcherhd@gmail.com> | 2012-05-15 10:38:20 +0000 |
commit | 48540940b6c28bb4378abfeb500ec45a625b37b6 (patch) | |
tree | 2ef294c0763e802f91d868bdef4229b6868527de /plugins/Popup/src/popup_wnd2.cpp | |
parent | 5c350913f011e119127baeb32a6aedeb4f0d33bc (diff) |
initial commit
git-svn-id: http://svn.miranda-ng.org/main/trunk@2 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/Popup/src/popup_wnd2.cpp')
-rw-r--r-- | plugins/Popup/src/popup_wnd2.cpp | 1945 |
1 files changed, 1945 insertions, 0 deletions
diff --git a/plugins/Popup/src/popup_wnd2.cpp b/plugins/Popup/src/popup_wnd2.cpp new file mode 100644 index 0000000000..785c0e706e --- /dev/null +++ b/plugins/Popup/src/popup_wnd2.cpp @@ -0,0 +1,1945 @@ +/*
+Popup Plus plugin for Miranda IM
+
+Copyright © 2002 Luca Santarelli,
+ © 2004-2007 Victor Pavlychko
+ © 2010 MPK
+ © 2010 Merlin_de
+
+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.
+
+===============================================================================
+
+File name : $HeadURL: http://svn.miranda.im/mainrepo/popup/trunk/src/popup_wnd2.cpp $
+Revision : $Revision: 1651 $
+Last change on : $Date: 2010-07-15 20:31:06 +0300 (Чт, 15 июл 2010) $
+Last change by : $Author: Merlin_de $
+
+===============================================================================
+*/
+
+#include "headers.h"
+#include "bitmap_funcs.h"
+#include <math.h>
+
+#define POPUP_WNDCLASS "PopupWnd2"
+
+#ifndef CS_DROPSHADOW
+#define CS_DROPSHADOW 0x00020000
+#endif
+
+#define ULW_ALPHA 0x00000002
+#define AC_SRC_ALPHA 0x01
+
+#define POPUP_TIMER 1607
+#define AVATAR_TIMER 1608
+#define CURSOR_TIMER 1609
+
+#define UM_AVATARCHANGED (WM_USER+0x300)
+#define UM_MENUDONE (WM_USER+0x301)
+#define UM_SHOWMENU (WM_USER+0x302)
+
+HWND ghwndMenuHost = NULL;
+
+void WindowThread(void *arg);
+
+LRESULT CALLBACK MenuHostWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+
+bool LoadPopupWnd2()
+{
+ bool res = true;
+ DWORD err;
+
+ WNDCLASSEX wcl;
+ wcl.cbSize = sizeof(wcl);
+ wcl.lpfnWndProc = PopupWnd2::WindowProc;
+ wcl.style = 0;
+ wcl.cbClsExtra = 0;
+ wcl.cbWndExtra = 0;
+ wcl.hInstance = hInst;
+ wcl.hIcon = NULL;
+ wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wcl.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
+ wcl.lpszMenuName = NULL;
+ wcl.lpszClassName = _T(POPUP_WNDCLASS);
+ wcl.hIconSm = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_POPUP), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);
+ g_wndClass.cPopupWnd2 = RegisterClassEx(&wcl);
+ err = GetLastError();
+ if (!g_wndClass.cPopupWnd2) {
+ res = false;
+ TCHAR msg[1024];
+ wsprintf(msg, TranslateT("Failed to register %s class."),wcl.lpszClassName);
+ MessageBox(NULL, msg, _T(MODULNAME_LONG), MB_ICONSTOP|MB_OK);
+ }
+
+ // register custom class for edit box with drop-shadow attribute
+ if (IsWinVerXPPlus())
+ {
+ #if defined(_UNICODE) || defined(_WIN64)
+ #define MyRegisterClassExW RegisterClassExW
+ #define MyGetClassInfoExW GetClassInfoExW
+ #else
+ ATOM (WINAPI *MyRegisterClassExW)(CONST WNDCLASSEXW *);
+ MyRegisterClassExW = (ATOM (WINAPI *)(CONST WNDCLASSEXW *))GetProcAddress(hUserDll, "RegisterClassExW");
+ BOOL (WINAPI *MyGetClassInfoExW)(HINSTANCE, LPCWSTR, LPWNDCLASSEXW);
+ MyGetClassInfoExW = (BOOL (WINAPI *)(HINSTANCE, LPCWSTR, LPWNDCLASSEXW))GetProcAddress(hUserDll, "GetClassInfoExW");
+ #endif
+ WNDCLASSEXW wclw = {0};
+ wclw.cbSize = sizeof(wclw);
+ if (!MyGetClassInfoExW(NULL, L"EDIT", &wclw))
+ MSGERROR(TranslateT("Failed to GetClassInfoExW from EDIT class."));
+ wclw.hInstance = hInst;
+ wclw.lpszClassName = L"PopupEditBox";
+ wclw.style |= CS_DROPSHADOW;
+ g_wndClass.cPopupEditBox = MyRegisterClassExW(&wclw);
+ err = GetLastError();
+ if (!g_wndClass.cPopupEditBox) {
+ TCHAR msg[2048];
+ wsprintf(msg, _T("Failed to register custom edit box window class.\r\n\r\ncbSize: %i\r\nstyle: %p\r\nlpfnWndProc: %i\r\ncbClsExtra: %i\r\ncbWndExtra: %i\r\nhInstance: %i\r\nhIcon: %i\r\nhCursor: %i\r\nhbrBackground: %i\r\nlpszMenuName: %s\r\nlpszClassName: %s\r\nhIconSm: %i\r\n"),
+ wclw.cbSize, //UINT cbSize;
+ wclw.style, //UINT style;
+ wclw.lpfnWndProc, //WNDPROC lpfnWndProc;
+ wclw.cbClsExtra, //int cbClsExtra;
+ wclw.cbWndExtra, //int cbWndExtra;
+ wclw.hInstance, //HINSTANCE hInstance;
+ wclw.hIcon, //HICON hIcon;
+ wclw.hCursor, //HCURSOR hCursor;
+ wclw.hbrBackground, //HBRUSH hbrBackground;
+ wclw.lpszMenuName, //LPCWSTR lpszMenuName;
+ wclw.lpszClassName, //LPCWSTR lpszClassName;
+ wclw.hIconSm //HICON hIconSm;
+ );
+
+ MSGERROR(msg);
+ }
+ }
+
+ ZeroMemory(&wcl, sizeof(wcl));
+ wcl.cbSize = sizeof(wcl);
+ wcl.lpfnWndProc = MenuHostWndProc;
+ wcl.style = 0;
+ wcl.cbClsExtra = 0;
+ wcl.cbWndExtra = 0;
+ wcl.hInstance = hInst;
+ wcl.hIcon = NULL;
+ wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wcl.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
+ wcl.lpszMenuName = NULL;
+ wcl.lpszClassName = _T("PopupMenuHostWnd");
+ wcl.hIconSm = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_POPUP), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);
+ g_wndClass.cPopupMenuHostWnd = RegisterClassEx(&wcl);
+ err = GetLastError();
+ if (!g_wndClass.cPopupMenuHostWnd) {
+ res = false;
+ TCHAR msg[1024];
+ wsprintf(msg, TranslateT("Failed to register %s class."),wcl.lpszClassName);
+ MSGERROR(msg);
+ }
+
+ ghwndMenuHost = CreateWindow(_T("PopupMenuHostWnd"), NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, NULL, hInst, NULL);
+ SetWindowPos(ghwndMenuHost, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_HIDEWINDOW);
+
+ INITCOMMONCONTROLSEX iccex;
+ iccex.dwICC = ICC_WIN95_CLASSES;
+ iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+ InitCommonControlsEx(&iccex);
+
+ res = res && ghwndMenuHost;
+
+ return res;
+}
+
+void UnloadPopupWnd2()
+{
+ DestroyWindow(ghwndMenuHost);
+}
+
+PopupWnd2::PopupWnd2(POPUPDATA2 *ppd, POPUPOPTIONS *theCustomOptions, bool renderOnly)
+{
+ m_signature = POPUP_OBJECT_SIGNARURE;
+
+ m_lockCount = 0;
+ m_hbmAvatar = NULL;
+ m_avatar = NULL;
+ m_textType = TT_NONE;
+ m_options = theCustomOptions ? theCustomOptions : &PopUpOptions;
+ m_lpzSkin = NULL;
+ m_customPopup = false;
+ m_lpwzTitle = m_lpwzText = NULL;
+ m_lpzTitle = m_lpzText = NULL;
+ m_mtTitle = m_mtText = NULL;
+ m_hfnText = fonts.text;
+ m_hfnTitle = fonts.title;
+ m_hwnd = m_hwndToolTip = NULL;
+ m_bPositioned = m_bIsHovered = /*m_bIdleRequested =*/ m_bWindowCreated = m_bFade = m_bSlide = m_bDestroy = false;
+ m_bmp = m_bmpBase = m_bmpAnimate = NULL;
+ m_avatarFrameDelay = 0;
+ m_hhkAvatarChanged = NULL;
+ m_actions = NULL;
+ m_actionCount = 0;
+ m_bIsPinned = false;
+ updateData(ppd);
+ if (!renderOnly)
+ startThread();
+}
+
+
+PopupWnd2::~PopupWnd2()
+{
+ m_signature = 0;
+
+ if (m_lpzSkin) mir_free(m_lpzSkin);
+ if (m_hwnd) SetWindowLongPtr(m_hwnd, GWLP_USERDATA, 0);
+ if (m_bmp) delete m_bmp;
+ if (m_bmpBase) delete m_bmpBase;
+ if (m_bmpAnimate) delete m_bmpAnimate;
+ mir_free(m_lpzText); mir_free(m_lpzTitle);
+ mir_free(m_lpwzText); mir_free(m_lpwzTitle);
+ if (m_mtText) MText.Destroy(m_mtText);
+ if (m_mtTitle) MText.Destroy(m_mtTitle);
+ if (m_avatar) delete m_avatar;
+ if (m_actions) delete [] m_actions;
+}
+
+void PopupWnd2::startThread()
+{
+ _beginthread(WindowThread, 0, this);
+}
+
+void PopupWnd2::create()
+{
+ m_hwnd = CreateWindowEx(
+ WS_EX_TRANSPARENT| // prevents unwanted clicks
+ WS_EX_TOOLWINDOW|WS_EX_TOPMOST, // dwStyleEx
+ _T(POPUP_WNDCLASS), // Class name
+ NULL, // Title
+ DS_SETFONT|DS_FIXEDSYS|WS_POPUP, // dwStyle
+ CW_USEDEFAULT, // x
+ CW_USEDEFAULT, // y
+ CW_USEDEFAULT, // Width
+ CW_USEDEFAULT, // Height
+ HWND_DESKTOP, // Parent
+ NULL, // menu handle
+ hInst, // Instance
+ (LPVOID)this);
+
+ // Shadows
+ if (IsWinVerXPPlus())
+ {
+ ULONG_PTR style = GetClassLongPtr(m_hwnd, GCL_STYLE);
+ if (m_options->DropShadow && !(style & CS_DROPSHADOW)) {
+ style |= CS_DROPSHADOW;
+ }
+ else if (!m_options->DropShadow && (style & CS_DROPSHADOW)){
+ style &= ~CS_DROPSHADOW;
+ }
+ SetClassLongPtr(m_hwnd, GCL_STYLE, style);
+ }
+
+ // tooltips
+ m_hwndToolTip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL,
+ WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ m_hwnd, NULL, hInst, NULL);
+ SetWindowPos(m_hwndToolTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+
+ m_bWindowCreated = true;
+ update();
+}
+
+void PopupWnd2::updateLayered(BYTE opacity)
+{
+ if (!m_hwnd) return;
+#if defined(_UNICODE)
+ if (SetWindowLong(m_hwnd, GWL_EXSTYLE, GetWindowLong(m_hwnd, GWL_EXSTYLE) | WS_EX_LAYERED)) {
+ RECT rc; GetWindowRect(m_hwnd, &rc);
+ POINT ptDst = {rc.left, rc.top};
+ POINT ptSrc = {0, 0};
+
+ BLENDFUNCTION blend;
+ blend.BlendOp = AC_SRC_OVER;
+ blend.BlendFlags = 0;
+ blend.SourceConstantAlpha = opacity; //m_options->UseTransparency ? opacity : 255;
+ blend.AlphaFormat = AC_SRC_ALPHA;
+
+ UpdateLayeredWindow(m_hwnd, NULL, &ptDst, &m_sz,
+ m_bmpAnimate ? m_bmpAnimate->getDC() : m_bmp->getDC(),
+ &ptSrc, 0xffffffff, &blend, ULW_ALPHA);
+
+ UpdateWindow(m_hwnd);
+ }
+#else
+ if (MyUpdateLayeredWindow) {
+ if (SetWindowLong(m_hwnd, GWL_EXSTYLE, GetWindowLong(m_hwnd, GWL_EXSTYLE) | WS_EX_LAYERED))
+ {
+ RECT rc; GetWindowRect(m_hwnd, &rc);
+ POINT ptDst = {rc.left, rc.top};
+ POINT ptSrc = {0, 0};
+
+ BLENDFUNCTION blend;
+ blend.BlendOp = AC_SRC_OVER;
+ blend.BlendFlags = 0;
+ blend.SourceConstantAlpha = opacity; //m_options->UseTransparency ? opacity : 255;
+ blend.AlphaFormat = AC_SRC_ALPHA;
+
+ MyUpdateLayeredWindow(m_hwnd, NULL, &ptDst, &m_sz,
+ m_bmpAnimate ? m_bmpAnimate->getDC() : m_bmp->getDC(),
+ &ptSrc, 0xffffffff, &blend, ULW_ALPHA);
+
+ UpdateWindow(m_hwnd);
+ }
+ }
+#endif
+}
+
+SIZE PopupWnd2::measure()
+{
+ const PopupSkin *skin = skins.getSkin(m_lpzSkin?m_lpzSkin:m_options->SkinPack);
+ if (!skin) return m_sz;
+
+ MyBitmap bmpTmp(1,1);
+ skin->measure(bmpTmp.getDC(), this, m_options->UseMaximumWidth ? m_options->MaximumWidth : SETTING_MAXIMUMWIDTH_MAX, m_options);
+ return m_sz;
+}
+
+void PopupWnd2::update()
+{
+ const PopupSkin *skin = skins.getSkin(m_lpzSkin?m_lpzSkin:m_options->SkinPack);
+ if (!skin) return;
+
+ // update avatar
+ fixAvatar();
+
+ // destroy content bitmap so animate() can reallocate it if needed
+ if (m_bmp)
+ {
+ delete m_bmp;
+ m_bmp = NULL;
+ }
+
+ // measure popup
+ if (m_bmpBase) delete m_bmpBase;
+ if (m_bmpAnimate) delete m_bmpAnimate;
+ m_bmpBase = new MyBitmap(1,1);
+ skin->measure(m_bmpBase->getDC(), this, m_options->UseMaximumWidth ? m_options->MaximumWidth : SETTING_MAXIMUMWIDTH_MAX, m_options);
+
+ // render popup
+ m_bmpBase->allocate(m_sz.cx, m_sz.cy);
+ HDC hdc = m_bmpBase->getDC();
+ if (!skin) return;
+ SetBkMode(hdc, TRANSPARENT);
+ skin->display(m_bmpBase, this, m_options->UseMaximumWidth ? m_options->MaximumWidth : SETTING_MAXIMUMWIDTH_MAX, m_options,
+ PopupSkin::DF_STATIC);
+ if (*m_time && skin->useInternalClock())
+ {
+ SetTextColor(hdc, m_clClock);
+ HFONT hfnSave = (HFONT)SelectObject(m_bmpBase->getDC(), fonts.clock);
+ SIZE sz; GetTextExtentPoint32A(m_bmpBase->getDC(), m_time, lstrlenA(m_time), &sz);
+ m_bmpBase->Draw_TextA(m_time, this->m_sz.cx - sz.cx - STYLE_SZ_GAP - skin->getRightGap(), STYLE_SZ_GAP);
+ SelectObject(m_bmpBase->getDC(), hfnSave);
+ }
+
+ m_bReshapeWindow = true;
+
+ animate();
+}
+
+void PopupWnd2::animate()
+{
+ const PopupSkin *skin = skins.getSkin(m_lpzSkin?m_lpzSkin:m_options->SkinPack);
+ if (!skin) return;
+
+ if (m_avatar->isAnimated() || m_actionCount)
+ {
+ if (!m_bmp) m_bmp = new MyBitmap(m_bmpBase->getWidth(), m_bmpBase->getHeight());
+ m_bmp->Draw(m_bmpBase, 0, 0, m_bmpBase->getWidth(), m_bmpBase->getHeight());
+ skin->display(m_bmp, this, m_options->UseMaximumWidth ? m_options->MaximumWidth : SETTING_MAXIMUMWIDTH_MAX, m_options, PopupSkin::DF_ANIMATE);
+ } else
+ if (m_bmpBase)
+ {
+ if (m_bmp) delete m_bmp;
+ m_bmp = m_bmpBase;
+ m_bmpBase = NULL;
+ }
+
+ // update layered window if supported
+ updateLayered((m_options->UseTransparency && !(m_bIsHovered && m_options->OpaqueOnHover)) ? m_options->Alpha : 255);
+
+ if (m_bReshapeWindow)
+ {
+ m_bReshapeWindow = false;
+#if defined(_UNICODE)
+ if (m_hwnd && m_bmp && m_options->DropShadow && PopUpOptions.EnableFreeformShadows /*DoWeNeedRegionForThisSkin()*/)
+ SetWindowRgn(m_hwnd, m_bmp->buildOpaqueRgn(skin->getShadowRegionOpacity()), FALSE);
+#else
+ if (!MyUpdateLayeredWindow && m_hwnd && m_bmp && PopUpOptions.Enable9xTransparency)
+ SetWindowRgn(m_hwnd, m_bmp->buildOpaqueRgn(skin->getLegacyRegionOpacity()), FALSE);
+
+ if (MyUpdateLayeredWindow && m_hwnd && m_bmp && m_options->DropShadow && PopUpOptions.EnableFreeformShadows /*DoWeNeedRegionForThisSkin()*/)
+ SetWindowRgn(m_hwnd, m_bmp->buildOpaqueRgn(skin->getShadowRegionOpacity()), FALSE);
+#endif
+
+ if (MyDwmEnableBlurBehindWindow && PopUpOptions.EnableAeroGlass)
+ {
+ DWM_BLURBEHIND bb = {0};
+ bb.dwFlags = DWM_BB_ENABLE|DWM_BB_BLURREGION;
+ bb.fEnable = TRUE;
+ bb.hRgnBlur = m_bmp->buildOpaqueRgn(254, false);
+ MyDwmEnableBlurBehindWindow(m_hwnd, &bb);
+ }
+
+ // update tooltips
+ for (int i = 0; i < m_actionCount; ++i)
+ {
+ char *title = strchr(m_actions[i].actionA.lpzTitle, '/');
+ if (title) title++;
+ else title = m_actions[i].actionA.lpzTitle;
+ AddTooltipTranslated(m_hwndToolTip, m_hwnd, i, m_actions[i].rc, title);
+ }
+
+// if (!customPopup && hwnd /*&& IsWindowVisible(hwnd)*/)
+// PopupThreadUpdateWindow(this);
+ }
+}
+
+void PopupWnd2::show()
+{
+ if ((m_options->UseEffect || (m_options->UseAnimations && !m_customPopup)) && m_options->FadeIn)
+ {
+ IPopupPlusEffect *effect = NULL;
+ m_bSlide = m_bFade = false;
+ DWORD dwTime, dwTime0 = GetTickCount();
+ DWORD dwTime1 = dwTime0 + m_options->FadeIn;
+ if (m_options->UseEffect)
+ {
+ m_bFade = true;
+ m_btAlpha0 = 0;
+ m_btAlpha1 = m_options->UseTransparency ? m_options->Alpha : 255;
+ updateLayered(m_btAlpha0);
+
+ if (*PopUpOptions.Effect)
+ {
+ char vfxService[128];
+ mir_snprintf(vfxService, sizeof(vfxService), "PopUp/Vfx/"TCHAR_STR_PARAM, PopUpOptions.Effect);
+ if (ServiceExists(vfxService))
+ if (effect = (IPopupPlusEffect *)CallService(vfxService, 0, 0))
+ {
+ effect->beginEffect(m_bmp->getWidth(), m_bmp->getHeight(), m_btAlpha0, m_btAlpha1, dwTime1-dwTime0);
+ m_bmpAnimate = new MyBitmap(m_bmp->getWidth(), m_bmp->getHeight());
+ }
+ }
+ } else
+ {
+ updateLayered(m_options->UseTransparency ? m_options->Alpha : 255);
+ }
+ if (m_options->UseAnimations && !m_customPopup)
+ {
+ m_bSlide = true;
+ m_ptPosition0 = m_pos;
+ m_ptPosition1 = m_pos;
+ if (m_options->Position == POS_LOWERLEFT || m_options->Position == POS_UPPERLEFT)
+ m_ptPosition0.x -= m_sz.cx + 2 * 5;
+ else
+ m_ptPosition0.x += m_sz.cx + 2 * 5;
+ SetWindowPos(m_hwnd, 0, m_ptPosition0.x, m_ptPosition0.y, 0, 0, SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_SHOWWINDOW);
+ } else
+ {
+ SetWindowPos(m_hwnd, 0, m_pos.x, m_pos.y, 0, 0, SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_SHOWWINDOW);
+ }
+ while ((dwTime = GetTickCount()) < dwTime1)
+ {
+ if (m_bFade)
+ {
+ if (effect)
+ {
+ effect->beginFrame(dwTime - dwTime0);
+ m_bmpAnimate->Draw(m_bmp, 0, 0, m_bmp->getWidth(), m_bmp->getHeight());
+ for (int row = 0; row < m_bmpAnimate->getHeight(); ++row)
+ {
+ unsigned char *pixel = (unsigned char *)m_bmpAnimate->getRow(row);
+ for (int col = 0; col < m_bmpAnimate->getWidth(); ++col)
+ {
+ WORD alphaLevel = effect->getPixelAlpha(col, row);
+ pixel[0] = (pixel[0] * alphaLevel) >> 8;
+ pixel[1] = (pixel[1] * alphaLevel) >> 8;
+ pixel[2] = (pixel[2] * alphaLevel) >> 8;
+ pixel[3] = (pixel[3] * alphaLevel) >> 8;
+ pixel += 4;
+ }
+ }
+ effect->endFrame();
+ updateLayered(255);
+ } else
+ {
+ updateLayered(m_btAlpha0 + (m_btAlpha1 - m_btAlpha0) * int(dwTime - dwTime0) / m_options->FadeIn);
+ }
+ }
+ if (m_bSlide)
+ SetWindowPos(m_hwnd, 0,
+ (int)m_ptPosition0.x + ((int)m_ptPosition1.x - (int)m_ptPosition0.x) * int(dwTime - dwTime0) / (int)m_options->FadeIn,
+ (int)m_ptPosition0.y + ((int)m_ptPosition1.y - (int)m_ptPosition0.y) * int(dwTime - dwTime0) / (int)m_options->FadeIn,
+ 0, 0, SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_SHOWWINDOW);
+ UpdateWindow(m_hwnd);
+ Sleep(1);
+ }
+
+ if (effect)
+ {
+ effect->endEffect();
+ effect->destroy();
+ delete m_bmpAnimate;
+ m_bmpAnimate = NULL;
+ }
+ }
+
+ m_bSlide = m_bFade = false;
+
+ updateLayered((m_options->UseTransparency && !(m_bIsHovered && m_options->OpaqueOnHover)) ? m_options->Alpha : 255);
+ //updateLayered(m_options->UseTransparency ? m_options->Alpha : 255);
+ SetWindowPos(m_hwnd, 0, m_pos.x, m_pos.y, 0, 0, SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_SHOWWINDOW);
+}
+
+void PopupWnd2::hide()
+{
+ if ((m_options->UseEffect || (m_options->UseAnimations && !m_customPopup)) && m_options->FadeOut)
+ {
+ m_bDestroy = true;
+ IPopupPlusEffect *effect = NULL;
+ m_bFade = m_bSlide = false;
+ DWORD dwTime, dwTime0 = GetTickCount();
+ DWORD dwTime1 = dwTime0 + m_options->FadeOut;
+ if (m_options->UseEffect)
+ {
+ m_bFade = true;
+ m_btAlpha0 = m_options->UseTransparency ? m_options->Alpha : 255;
+ m_btAlpha1 = 0;
+ updateLayered(m_btAlpha0);
+
+ if (*PopUpOptions.Effect)
+ {
+ char vfxService[128];
+ mir_snprintf(vfxService, sizeof(vfxService), "PopUp/Vfx/"TCHAR_STR_PARAM, PopUpOptions.Effect);
+ if (ServiceExists(vfxService))
+ if (effect = (IPopupPlusEffect *)CallService(vfxService, 0, 0))
+ {
+ effect->beginEffect(m_bmp->getWidth(), m_bmp->getHeight(), m_btAlpha0, m_btAlpha1, dwTime1-dwTime0);
+ m_bmpAnimate = new MyBitmap(m_bmp->getWidth(), m_bmp->getHeight());
+ }
+ }
+ }
+ if (m_options->UseAnimations && !m_customPopup)
+ {
+ m_bSlide = true;
+ m_ptPosition0 = m_pos;
+ m_ptPosition1 = m_pos;
+ if (m_options->Position == POS_LOWERLEFT || m_options->Position == POS_UPPERLEFT)
+ m_ptPosition1.x -= m_sz.cx + 2 * 5;
+ else
+ m_ptPosition1.x += m_sz.cx + 2 * 5;
+ SetWindowPos(m_hwnd, 0, m_ptPosition0.x, m_ptPosition0.y, 0, 0, SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_SHOWWINDOW);
+ }
+ while ((dwTime = GetTickCount()) < dwTime1)
+ {
+ if (m_bFade)
+ {
+ if (effect)
+ {
+ effect->beginFrame(dwTime - dwTime0);
+ m_bmpAnimate->Draw(m_bmp, 0, 0, m_bmp->getWidth(), m_bmp->getHeight());
+ for (int row = 0; row < m_bmpAnimate->getHeight(); ++row)
+ {
+ unsigned char *pixel = (unsigned char *)m_bmpAnimate->getRow(row);
+ for (int col = 0; col < m_bmpAnimate->getWidth(); ++col)
+ {
+ WORD alphaLevel = effect->getPixelAlpha(col, row);
+ pixel[0] = (pixel[0] * alphaLevel) >> 8;
+ pixel[1] = (pixel[1] * alphaLevel) >> 8;
+ pixel[2] = (pixel[2] * alphaLevel) >> 8;
+ pixel[3] = (pixel[3] * alphaLevel) >> 8;
+ pixel += 4;
+ }
+ }
+ effect->endFrame();
+ updateLayered(255);
+ } else
+ {
+ updateLayered((int)m_btAlpha0 + ((int)m_btAlpha1 - (int)m_btAlpha0) * int(dwTime - dwTime0) / (int)m_options->FadeOut);
+ }
+ }
+ if (m_bSlide)
+ SetWindowPos(m_hwnd, 0,
+ (int)m_ptPosition0.x + ((int)m_ptPosition1.x - (int)m_ptPosition0.x) * int(dwTime - dwTime0) / (int)m_options->FadeOut,
+ (int)m_ptPosition0.y + ((int)m_ptPosition1.y - (int)m_ptPosition0.y) * int(dwTime - dwTime0) / (int)m_options->FadeOut,
+ 0, 0, SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_SHOWWINDOW);
+ UpdateWindow(m_hwnd);
+ Sleep(1);
+ }
+
+ if (effect)
+ {
+ effect->endEffect();
+ effect->destroy();
+ delete m_bmpAnimate;
+ m_bmpAnimate = NULL;
+ }
+ }
+
+ SetWindowPos(m_hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_HIDEWINDOW);
+ DestroyWindow(m_hwnd);
+// hwnd = 0;
+}
+
+bool __forceinline isTextEmpty(char *text)
+{
+ if (!text)
+ return true;
+ while (*text)
+ if (!isspace(BYTE(*text++)))
+ return false;
+ return true;
+}
+
+bool __forceinline isTextEmpty(WCHAR *text)
+{
+ if (!text)
+ return true;
+ while (*text)
+ if (!iswspace(*text++))
+ return false;
+ return true;
+}
+
+void PopupWnd2::fixDefaults()
+{
+ if (m_options->UseWinColors)
+ {
+ m_clBack = GetSysColor(COLOR_BTNFACE);
+ m_clText = GetSysColor(COLOR_WINDOWTEXT);
+ m_clTitle = GetSysColor(COLOR_WINDOWTEXT);
+ m_clClock = GetSysColor(COLOR_WINDOWTEXT);
+ } else
+ if ((m_clBack == (COLORREF)NULL) && (m_clText == (COLORREF)NULL))
+ {
+ m_clTitle = fonts.clTitle;
+ m_clBack = fonts.clBack;
+ m_clText = fonts.clText;
+ m_clClock = fonts.clClock;
+ } else
+ {
+ m_clClock = m_clTitle;
+ }
+
+ if (!m_iTimeout)
+ {
+ m_iTimeout = m_options->InfiniteDelay ? -1 : m_options->Seconds;
+ }
+
+ m_hContactPassed = m_hContact;
+ if (m_hContact)
+ {
+ if (!CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)m_hContact, 0))
+ m_hContact = NULL;
+ }
+
+ switch (m_textType)
+ {
+ case TT_ANSI:
+ m_bTextEmpty = ::isTextEmpty(m_lpzText);
+ break;
+
+ case TT_UNICODE:
+ m_bTextEmpty = ::isTextEmpty(m_lpwzText);
+ break;
+
+ default:
+ m_bTextEmpty = false;
+ break;
+ }
+}
+
+void PopupWnd2::fixAvatar()
+{
+ if (m_avatar && !m_avatar->isValid())
+ delete m_avatar;
+
+ if (m_hbmAvatar)
+ {
+ m_avatar = new SimpleAvatar(m_hbmAvatar, true);
+ } else
+ {
+ m_avatar = PopupAvatar::create(m_hContact);
+ }
+}
+
+int PopupWnd2::fixActions(POPUPACTION *theActions, int count)
+{
+ bool isIm = (m_hContact &&
+ (CallProtoService(
+ (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)m_hContact, 0),
+ PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IM)) ? true : false;
+
+// bool enableDefault = (isIm || !(PopUpOptions.actions&ACT_DEF_IMONLY)) ? true : false;
+ bool enableDefaultGen = (m_hContact || !(PopUpOptions.actions&ACT_DEF_NOGLOBAL)) ? true : false;
+ bool enableDefaultUsr = (isIm || m_hContact && !(PopUpOptions.actions&ACT_DEF_IMONLY)) ? true : false;
+ bool iconSize = PopUpOptions.actions&ACT_LARGE ? TRUE : FALSE;
+
+ if (PopUpOptions.actions&ACT_ENABLE)
+ {
+ if (enableDefaultUsr && isIm && IsActionEnabled("General/Quick reply")) ++m_actionCount;
+ if (enableDefaultUsr && isIm && IsActionEnabled("General/Send message")) ++m_actionCount;
+ if (enableDefaultUsr && IsActionEnabled("General/User details")) ++m_actionCount;
+ if (enableDefaultUsr && IsActionEnabled("General/Contact menu")) ++m_actionCount;
+ if (enableDefaultUsr && DBGetContactSettingByte(m_hContact, "CList", "NotOnList", 0) && IsActionEnabled("General/Add permanently")) ++m_actionCount;
+ if (enableDefaultGen && (m_iTimeout != -1) && IsActionEnabled("General/Pin popup")) ++m_actionCount;
+ if (enableDefaultGen && IsActionEnabled("General/Dismiss popup")) ++m_actionCount;
+ if (enableDefaultGen && IsActionEnabled("General/Copy to clipboard")) ++m_actionCount;
+
+ int iAction = fixActions(theActions, count, m_actionCount);
+
+ if (enableDefaultUsr && isIm && IsActionEnabled("General/Quick reply"))
+ {
+ m_actions[iAction].actionA.cbSize = sizeof(POPUPACTION);
+ m_actions[iAction].actionA.lchIcon = IcoLib_GetIcon(ICO_ACT_REPLY,iconSize);
+ lstrcpyA(m_actions[iAction].actionA.lpzTitle, "General/Quick reply");
+ m_actions[iAction].actionA.wParam = 0;
+ m_actions[iAction].actionA.lParam = ACT_DEF_REPLY;
+ ++iAction;
+ }
+ if (enableDefaultUsr && isIm && IsActionEnabled("General/Send message"))
+ {
+ m_actions[iAction].actionA.cbSize = sizeof(POPUPACTION);
+ m_actions[iAction].actionA.lchIcon = IcoLib_GetIcon(ICO_ACT_MESS,iconSize);
+ lstrcpyA(m_actions[iAction].actionA.lpzTitle, "General/Send message");
+ m_actions[iAction].actionA.wParam = 0;
+ m_actions[iAction].actionA.lParam = ACT_DEF_MESSAGE;
+ ++iAction;
+ }
+ if (enableDefaultUsr && IsActionEnabled("General/User details"))
+ {
+ m_actions[iAction].actionA.cbSize = sizeof(POPUPACTION);
+ m_actions[iAction].actionA.lchIcon = IcoLib_GetIcon(ICO_ACT_INFO,iconSize);
+ lstrcpyA(m_actions[iAction].actionA.lpzTitle, "General/User details");
+ m_actions[iAction].actionA.wParam = 0;
+ m_actions[iAction].actionA.lParam = ACT_DEF_DETAILS;
+ ++iAction;
+ }
+ if (enableDefaultUsr && IsActionEnabled("General/Contact menu"))
+ {
+ m_actions[iAction].actionA.cbSize = sizeof(POPUPACTION);
+ m_actions[iAction].actionA.lchIcon = IcoLib_GetIcon(ICO_ACT_MENU,iconSize);
+ lstrcpyA(m_actions[iAction].actionA.lpzTitle, "General/Contact menu");
+ m_actions[iAction].actionA.wParam = 0;
+ m_actions[iAction].actionA.lParam = ACT_DEF_MENU;
+ ++iAction;
+ }
+ if (enableDefaultUsr && DBGetContactSettingByte(m_hContact, "CList", "NotOnList", 0) && IsActionEnabled("General/Add permanently"))
+ {
+ m_actions[iAction].actionA.cbSize = sizeof(POPUPACTION);
+ m_actions[iAction].actionA.lchIcon = IcoLib_GetIcon(ICO_ACT_ADD,iconSize);
+ lstrcpyA(m_actions[iAction].actionA.lpzTitle, "General/Add permanently");
+ m_actions[iAction].actionA.wParam = 0;
+ m_actions[iAction].actionA.lParam = ACT_DEF_ADD;
+ ++iAction;
+ }
+ if (enableDefaultGen && (m_iTimeout != -1) && IsActionEnabled("General/Pin popup"))
+ {
+ m_actions[iAction].actionA.cbSize = sizeof(POPUPACTION);
+ m_actions[iAction].actionA.lchIcon = m_bIsPinned ? IcoLib_GetIcon(ICO_ACT_PINNED,iconSize) : IcoLib_GetIcon(ICO_ACT_PIN,iconSize);
+ lstrcpyA(m_actions[iAction].actionA.lpzTitle, "General/Pin popup");
+ m_actions[iAction].actionA.wParam = 0;
+ m_actions[iAction].actionA.lParam = ACT_DEF_PIN;
+ ++iAction;
+ }
+ if (enableDefaultGen && IsActionEnabled("General/Dismiss popup"))
+ {
+ m_actions[iAction].actionA.cbSize = sizeof(POPUPACTION);
+ m_actions[iAction].actionA.lchIcon = IcoLib_GetIcon(ICO_ACT_CLOSE,iconSize);
+ lstrcpyA(m_actions[iAction].actionA.lpzTitle, "General/Dismiss popup");
+ m_actions[iAction].actionA.wParam = 0;
+ m_actions[iAction].actionA.lParam = ACT_DEF_DISMISS;
+ ++iAction;
+ }
+ if (enableDefaultGen && IsActionEnabled("General/Copy to clipboard"))
+ {
+ m_actions[iAction].actionA.cbSize = sizeof(POPUPACTION);
+ m_actions[iAction].actionA.lchIcon = IcoLib_GetIcon(ICO_ACT_COPY,iconSize);
+ lstrcpyA(m_actions[iAction].actionA.lpzTitle, "General/Copy to clipboard");
+ m_actions[iAction].actionA.wParam = 0;
+ m_actions[iAction].actionA.lParam = ACT_DEF_COPY;
+ ++iAction;
+ }
+ }
+
+ return m_actionCount;
+}
+
+int PopupWnd2::fixActions(POPUPACTION *theActions, int count, int additional)
+{
+ m_actionCount = 0;
+ if (m_actions) delete [] m_actions;
+ m_actions = NULL;
+
+ int i;
+
+ m_actionCount = additional;
+ for (i = 0; i < count; ++i)
+ if ((theActions[i].flags&PAF_ENABLED) && IsActionEnabled(&theActions[i]))
+ ++m_actionCount;
+
+ m_actions = new ActionInfo[m_actionCount];
+ int iAction = 0;
+
+ for (i = 0; i < count; ++i)
+ if ((theActions[i].flags&PAF_ENABLED) && IsActionEnabled(&theActions[i]))
+ {
+ m_actions[iAction].actionA = theActions[i];
+ ++iAction;
+ }
+
+ return iAction;
+}
+
+void PopupWnd2::updateData(POPUPDATA *ppd)
+{
+ m_hContact = ppd->lchContact;
+
+ m_clBack = ppd->colorBack;
+ m_clClock = m_clTitle = m_clText = ppd->colorText;
+ m_iTimeout = m_options->DisplayTime;
+
+ mir_free(m_lpzText); mir_free(m_lpzTitle);
+ mir_free(m_lpwzText); mir_free(m_lpwzTitle);
+ if (m_textType == TT_NONE) m_textType = TT_ANSI;
+ m_lpzTitle = mir_strdup(ppd->lpzContactName);
+ m_lpzText = mir_strdup(ppd->lpzText);
+ m_lpwzTitle = m_lpwzText = NULL;
+// mtTitle = mtText = NULL;
+ // hfnTitle, hfnText;
+ m_hIcon = ppd->lchIcon;
+
+ m_PluginData = ppd->PluginData;
+ m_PluginWindowProc = ppd->PluginWindowProc;
+
+ if (m_options->DisplayTime)
+ GetTimeFormatA(LOCALE_USER_DEFAULT, 0, NULL,"HH':'mm", m_time, SIZEOF(m_time));
+ else m_time[0] = 0;
+
+ fixDefaults();
+
+ if (m_textType == TT_MTEXT) buildMText();
+}
+
+void PopupWnd2::updateData(POPUPDATAEX_V2 *ppd)
+{
+ m_hContact = ppd->lchContact;
+
+ m_clBack = ppd->colorBack;
+ m_clClock = m_clTitle = m_clText = ppd->colorText;
+ m_iTimeout = ppd->iSeconds ? ppd->iSeconds : m_options->Seconds;
+
+ if (m_textType == TT_NONE) m_textType = TT_ANSI;
+ mir_free(m_lpzText); mir_free(m_lpzTitle);
+ mir_free(m_lpwzText); mir_free(m_lpwzTitle);
+ m_lpzTitle = mir_strdup(ppd->lpzContactName);
+ m_lpzText = mir_strdup(ppd->lpzText);
+ m_lpwzTitle = m_lpwzText = NULL;
+// mtTitle = mtText = NULL;
+ // hfnTitle, hfnText;
+ m_hIcon = ppd->lchIcon;
+ m_hNotification = ppd->hNotification;
+
+ m_PluginData = ppd->PluginData;
+ m_PluginWindowProc = ppd->PluginWindowProc;
+
+ if (m_options->DisplayTime)
+ GetTimeFormatA(LOCALE_USER_DEFAULT, 0, NULL,"HH':'mm", m_time, SIZEOF(m_time));
+ else m_time[0] = 0;
+
+ fixDefaults();
+ fixActions(ppd->lpActions, ppd->actionCount);
+
+ if (m_textType == TT_MTEXT) buildMText();
+}
+
+void PopupWnd2::updateData(POPUPDATAW_V2 *ppd)
+{
+ m_hContact = ppd->lchContact;
+
+ m_clBack = ppd->colorBack;
+ m_clClock = m_clTitle = m_clText = ppd->colorText;
+ m_iTimeout = ppd->iSeconds ? ppd->iSeconds : m_options->Seconds;
+
+ if (m_textType == TT_NONE) m_textType = TT_UNICODE;
+ mir_free(m_lpzText); mir_free(m_lpzTitle);
+ mir_free(m_lpwzText); mir_free(m_lpwzTitle);
+ m_lpzTitle = m_lpzText = NULL;
+ m_lpwzTitle = mir_wstrdup(ppd->lpwzContactName);
+ m_lpwzText = mir_wstrdup(ppd->lpwzText);
+// mtTitle = mtText = NULL;
+ // hfnTitle, hfnText;
+ m_hIcon = ppd->lchIcon;
+ m_hNotification = ppd->hNotification;
+
+ m_PluginData = ppd->PluginData;
+ m_PluginWindowProc = ppd->PluginWindowProc;
+
+ if (m_options->DisplayTime)
+ GetTimeFormatA(LOCALE_USER_DEFAULT, 0, NULL,"HH':'mm", m_time, SIZEOF(m_time));
+ else m_time[0] = 0;
+
+ fixDefaults();
+ fixActions(ppd->lpActions, ppd->actionCount);
+
+ if (m_textType == TT_MTEXT) buildMText();
+}
+
+void PopupWnd2::updateData(POPUPDATA2 *ppd)
+{
+ m_hContact = ppd->lchContact;
+
+ m_clBack = ppd->colorBack;
+ m_clClock = m_clTitle = m_clText = ppd->colorText;
+ m_iTimeout = ppd->iSeconds;
+
+ mir_free(m_lpzText); mir_free(m_lpzTitle);
+ mir_free(m_lpwzText); mir_free(m_lpwzTitle);
+ if (ppd->flags&PU2_UNICODE)
+ {
+ if (m_textType == TT_NONE) m_textType = TT_UNICODE;
+ m_lpzTitle = m_lpzText = NULL;
+ m_lpwzTitle = mir_wstrdup(ppd->lpwzTitle);
+ m_lpwzText = mir_wstrdup(ppd->lpwzText);
+ m_lpzTitle = m_lpzText = NULL;
+ } else
+ {
+ if (m_textType == TT_NONE) m_textType = TT_ANSI;
+ m_lpzTitle = mir_strdup(ppd->lpzTitle);
+ m_lpzText = mir_strdup(ppd->lpzText);
+ m_lpwzTitle = m_lpwzText = NULL;
+ }
+
+ m_hIcon = ppd->lchIcon;
+ m_hNotification = ppd->lchNotification;
+
+ m_PluginData = ppd->PluginData;
+ m_PluginWindowProc = ppd->PluginWindowProc;
+ m_customPopup = (ppd->flags & PU2_CUSTOM_POPUP)!= 0;
+
+ m_hbmAvatar = ppd->hbmAvatar;
+ m_lpzSkin = mir_a2t(ppd->lpzSkin);
+
+ if (m_options->DisplayTime)
+ {
+ if (ppd->dwTimestamp)
+ {
+ DBTIMETOSTRING dbtts;
+ dbtts.szFormat = "t";
+ dbtts.szDest = m_time;
+ dbtts.cbDest = SIZEOF(m_time);
+ CallService(MS_DB_TIME_TIMESTAMPTOSTRING, (WPARAM)ppd->dwTimestamp, (LPARAM)&dbtts);
+ } else
+ {
+ GetTimeFormatA(LOCALE_USER_DEFAULT, 0, NULL,"HH':'mm", m_time, SIZEOF(m_time));
+ }
+ }
+ else m_time[0] = 0;
+
+ fixDefaults();
+ fixActions(ppd->lpActions, ppd->actionCount);
+
+ if (m_textType == TT_MTEXT) buildMText();
+}
+
+void PopupWnd2::buildMText()
+{
+ if (!(htuText && htuTitle && PopUpOptions.UseMText))
+ return;
+
+ if (m_mtText) MText.Destroy(m_mtText);
+ if (m_mtTitle)MText.Destroy(m_mtTitle);
+ m_mtText = m_mtTitle = NULL;
+
+ if (m_lpwzText && m_lpwzTitle) {
+ m_textType = TT_MTEXT;
+ m_mtText = MText.CreateW(htuText, m_lpwzText);
+ m_mtTitle = MText.CreateW(htuTitle,m_lpwzTitle);
+ }
+ else if (m_lpzText && m_lpzTitle) {
+ m_textType = TT_MTEXT;
+ if (ServiceExists(MS_TEXT_CREATEW)) {
+ LOGFONT lf;
+ LPWSTR lpwzBuf = NULL;
+
+ GetObject(m_hfnText, sizeof(lf), &lf);
+ lpwzBuf = mir_a2u(m_lpzText);
+ m_mtText = MText.CreateW(htuText, lpwzBuf);
+ mir_free(lpwzBuf); lpwzBuf = NULL;
+
+ GetObject(m_hfnTitle, sizeof(lf), &lf);
+ lpwzBuf = mir_a2u(m_lpzTitle);
+ m_mtTitle = MText.CreateW(htuTitle, lpwzBuf);
+ mir_free(lpwzBuf); lpwzBuf = NULL;
+ }
+ else {
+ m_mtText = MText.Create(htuText, m_lpzText);
+ m_mtTitle = MText.Create(htuTitle,m_lpzTitle);
+ }
+ }
+}
+
+void PopupWnd2::updateText(char *text)
+{
+ if (m_lpzText)
+ {
+ mir_free(m_lpzText);
+ m_lpzText = mir_strdup(text);
+ if (m_textType == TT_MTEXT)
+ buildMText();
+ }
+ m_bTextEmpty = ::isTextEmpty(m_lpzText);
+}
+
+void PopupWnd2::updateText(WCHAR *text)
+{
+ if (m_lpwzText)
+ {
+ mir_free(m_lpwzText);
+ m_lpwzText = mir_wstrdup(text);
+ if (m_textType == TT_MTEXT)
+ buildMText();
+ }
+ m_bTextEmpty = ::isTextEmpty(m_lpwzText);
+}
+
+void PopupWnd2::updateTitle(char *title)
+{
+ if (m_lpzTitle)
+ {
+ mir_free(m_lpzTitle);
+ m_lpzTitle = mir_strdup(title);
+ if (m_textType == TT_MTEXT)
+ buildMText();
+ }
+}
+
+void PopupWnd2::updateTitle(WCHAR *title)
+{
+ if (m_lpwzTitle)
+ {
+ mir_free(m_lpwzTitle);
+ m_lpwzTitle = mir_wstrdup(title);
+ if (m_textType == TT_MTEXT)
+ buildMText();
+ }
+}
+
+void PopupWnd2::updateTimer()
+{
+ KillTimer(m_hwnd, POPUP_TIMER);
+ if (m_iTimeout > 0)
+ SetTimer(m_hwnd, POPUP_TIMER, 1000, 0);
+}
+
+LRESULT CALLBACK NullWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_COMMAND:
+ case WM_CONTEXTMENU:
+ PUDeletePopUp(hwnd);
+ break;
+ }
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+struct ReplyEditData
+{
+ HWND hwndPopup;
+ HANDLE hContact;
+ WNDPROC oldWndProc;
+};
+
+bool IsMsgServiceNameW(HANDLE hContact) {
+ if (g_popup.isMirUnicode) {
+ char szServiceName[100];
+ char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (szProto == NULL)
+ return false;
+
+ mir_snprintf(szServiceName, sizeof(szServiceName), "%s%sW", szProto, PSS_MESSAGE);
+ if (ServiceExists(szServiceName))
+ return true;
+ }
+ return false;
+}
+
+BOOL IsUtfSendAvailable(HANDLE hContact)
+{
+ char* szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if(szProto == NULL) return FALSE;
+ //check for MetaContact and get szProto from subcontact
+ if(strcmp(szProto, gszMetaProto)==0) {
+ HANDLE hSubContact = (HANDLE)CallService(MS_MC_GETDEFAULTCONTACT, (WPARAM)hContact, 0);
+ if(!hSubContact) return FALSE;
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hSubContact, 0);
+ }
+ return(CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_4, 0) & PF4_IMSENDUTF) ? TRUE : FALSE;
+}
+
+void AddMessageToDB(HANDLE hContact, char *msg, int flag/*bool utf*/)
+{
+ DBEVENTINFO dbei = {0};
+ dbei.cbSize = sizeof(dbei);
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.flags = DBEF_SENT | ((flag&PREF_UTF)==PREF_UTF ? DBEF_UTF : 0);
+ dbei.szModule = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ dbei.timestamp = time(NULL);
+ if(g_popup.isOsUnicode && !((flag&PREF_UTF)==PREF_UTF) && (flag&PREF_UNICODE)==PREF_UNICODE)
+ dbei.cbBlob = (lstrlenW((LPWSTR)msg) + 1)*sizeof(WCHAR/*TCHAR*/);
+ else
+ dbei.cbBlob = lstrlenA(msg) + 1;
+ dbei.pBlob = (PBYTE)msg;
+ CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&dbei);
+}
+
+LRESULT CALLBACK ReplyEditWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ ReplyEditData *dat = (ReplyEditData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ WNDPROC oldWndProc = dat ? dat->oldWndProc : NULL;
+
+ switch (message)
+ {
+/*
+ case WM_ERASEBKGND:
+ {
+ HDC hdc = (HDC)wParam;
+ RECT rc; GetClientRect(hwnd, &rc);
+ FillRect(hdc, &rc, GetSysColorBrush(COLOR_WINDOW));
+ SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
+ DrawText(hdc, "Quick Reply", -1, &rc, DT_BOTTOM|DT_RIGHT|DT_SINGLELINE);
+ return TRUE;
+ }
+*/
+ case WM_KEYDOWN:
+ {
+ switch (wParam)
+ {
+ case VK_RETURN:
+ {
+ char *buf = NULL;
+ int flag = 0;
+ bool bSendW = IsMsgServiceNameW(dat->hContact);
+ //if (g_popup.isMirUnicode)
+ if (IsWindowUnicode(hwnd))
+ {
+ WCHAR msg[2048];
+ LPWSTR bufW = NULL;
+#if defined(_UNICODE)
+ SendMessageW(hwnd, WM_GETTEXT, SIZEOF(msg), (LPARAM)msg);
+#else
+ MySendMessageW(hwnd, WM_GETTEXT, SIZEOF(msg), (LPARAM)msg);
+#endif
+ if(wcslen(msg)==0){
+ DestroyWindow(hwnd);
+ return 0;
+ }
+ // we have unicode message, check if it is possible and reasonable to send it as unicode
+ if (IsUtfSendAvailable(dat->hContact)) {
+ buf = mir_utf8encodeW(msg);
+ flag = PREF_UTF;
+ }
+ else if(bSendW){
+ bufW = mir_wstrdup(msg) /*mir_tstrdup(msg)*/;
+ buf = (char*)bufW;
+ flag = PREF_UNICODE /*PREF_TCHAR*/;
+ }
+ else {
+ buf = mir_u2a(msg);
+ flag = 0;
+ }
+ }
+ else {
+ char msg[2048];
+ GetWindowTextA(hwnd, msg, SIZEOF(msg));
+ if(strlen(msg)==0){
+ DestroyWindow(hwnd);
+ return 0;
+ }
+ // we have message, check if it is possible and reasonable to send it as unicode
+ if ( IsUtfSendAvailable( dat->hContact )) {
+ buf = mir_utf8encode(msg);
+ flag = PREF_UTF;
+ }
+ else {
+ buf = mir_strdup(msg) /*mir_tstrdup(msg)*/;
+ flag = 0 /*PREF_TCHAR*/;
+ }
+ }
+
+ CallContactService(dat->hContact, bSendW ? (PSS_MESSAGE"W"):PSS_MESSAGE, flag, (LPARAM)buf);
+ AddMessageToDB(dat->hContact, buf, flag);
+ mir_free(buf);
+
+ DestroyWindow(hwnd);
+ return 0;
+ }
+ case VK_ESCAPE:
+ {
+ DestroyWindow(hwnd);
+ return 0;
+ }
+ }
+ break;
+ }
+
+ case WM_ACTIVATE:
+ if (wParam == WA_INACTIVE)
+ DestroyWindow(hwnd);
+ break;
+
+ case WM_DESTROY:
+ PopupThreadUnlock();
+ if (!(PopUpOptions.actions&ACT_DEF_KEEPWND))
+ PUDeletePopUp(dat->hwndPopup);
+ SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)dat->oldWndProc);
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
+ mir_free(dat);
+ }
+
+ if (oldWndProc)
+ {
+#if defined(_UNICODE)
+ return CallWindowProcW(oldWndProc, hwnd, message, wParam, lParam);
+#else
+ if (IsWindowUnicode(hwnd) && MyCallWindowProcW)
+ return MyCallWindowProcW(oldWndProc, hwnd, message, wParam, lParam);
+ return CallWindowProc(oldWndProc, hwnd, message, wParam, lParam);
+#endif
+ }
+
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+LRESULT CALLBACK PopupWnd2::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_CREATE:
+ {
+// show();
+ return DefWindowProc(m_hwnd, message, wParam, lParam);
+ break;
+ }
+
+ case UM_INITPOPUP:
+ {
+ if (!m_customPopup) PopupThreadAddWindow(this);
+ if (m_iTimeout > 0) SetTimer(m_hwnd, POPUP_TIMER, m_iTimeout*1000, 0);
+ if (m_hContact && !m_hbmAvatar && PopUpOptions.EnableAvatarUpdates)
+ m_hhkAvatarChanged = HookEventMessage(ME_AV_AVATARCHANGED, m_hwnd, UM_AVATARCHANGED);
+ if (m_avatar->activeFrameDelay() > 0) SetTimer(m_hwnd, AVATAR_TIMER, m_avatar->activeFrameDelay(), 0);
+
+ // prevent unwanted clicks, but allow wanted :)
+ GetCursorPos(&m_ptPrevCursor);
+ SetTimer(m_hwnd, CURSOR_TIMER, 500, NULL);
+
+ break;
+ }
+
+ case UM_POPUPSHOW:
+ {
+ POINT pt; pt.x = wParam; pt.y = lParam;
+ setPosition(pt);
+ show();
+ break;
+ }
+
+ case UM_AVATARCHANGED:
+ {
+ if ((HANDLE)wParam == m_hContact)
+ {
+ m_avatar->invalidate();
+ update();
+ if (m_avatar->activeFrameDelay() > 0) SetTimer(m_hwnd, AVATAR_TIMER, m_avatar->activeFrameDelay(), 0);
+ }
+ break;
+ }
+
+ case UM_POPUPACTION:
+ {
+ if (wParam != 0) break;
+ switch (lParam)
+ {
+ case ACT_DEF_MESSAGE:
+ CallServiceSync(MS_MSG_SENDMESSAGE, (WPARAM)m_hContact, 0);
+ if (!(PopUpOptions.actions&ACT_DEF_KEEPWND))
+ PUDeletePopUp(m_hwnd);
+ break;
+
+ case ACT_DEF_REPLY:
+ {
+ if (!m_customPopup) PopupThreadLock();
+ //RECT rc = renderInfo.textRect;
+ //MapWindowPoints(hwnd, NULL, (LPPOINT)&rc, 2);
+ RECT rc; GetWindowRect(m_hwnd, &rc);
+#if defined(_UNICODE)
+ HWND hwndEditBox = CreateWindowExW(WS_EX_TOOLWINDOW|WS_EX_TOPMOST,
+ g_wndClass.cPopupEditBox ? L"PopupEditBox" : L"EDIT",
+ NULL,
+ WS_BORDER|WS_POPUP|WS_VISIBLE|ES_AUTOVSCROLL|ES_LEFT|ES_MULTILINE|ES_NOHIDESEL|ES_WANTRETURN,
+ rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, NULL, NULL, hInst, NULL);
+#else
+ HWND hwndEditBox = 0;
+ if(MyCreateWindowExW && g_popup.isMirUnicode) {
+ //create unicode window only if miranda is unicode
+ //coz many protocol make trouble with unicode text on utf8 send inside ansi release
+ hwndEditBox = MyCreateWindowExW(WS_EX_TOOLWINDOW|WS_EX_TOPMOST,
+ g_wndClass.cPopupEditBox ? L"PopupEditBox" : L"EDIT",
+ NULL,
+ WS_BORDER|WS_POPUP|WS_VISIBLE|ES_AUTOVSCROLL|ES_LEFT|ES_MULTILINE|ES_NOHIDESEL|ES_WANTRETURN,
+ rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, NULL, NULL, hInst, NULL);
+ }
+ else {
+ hwndEditBox = CreateWindowExA(WS_EX_TOOLWINDOW|WS_EX_TOPMOST,
+ g_wndClass.cPopupEditBox ? "PopupEditBox" : "EDIT",
+ NULL,
+ WS_BORDER|WS_POPUP|WS_VISIBLE|ES_AUTOVSCROLL|ES_LEFT|ES_MULTILINE|ES_NOHIDESEL|ES_WANTRETURN,
+ rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, NULL, NULL, hInst, NULL);
+ }
+#endif
+ ReplyEditData *dat = (ReplyEditData *)mir_alloc(sizeof(ReplyEditData));
+ dat->oldWndProc = (WNDPROC)GetWindowLongPtr(hwndEditBox, (LONG_PTR)GWLP_WNDPROC);
+ dat->hwndPopup = m_hwnd;
+ dat->hContact = m_hContact;
+ if(IsWindowUnicode(hwndEditBox)) {
+#if defined(_UNICODE)
+ SendMessageW(hwndEditBox, WM_SETFONT, (WPARAM)fonts.text, TRUE);
+#else
+ MySendMessageW(hwndEditBox, WM_SETFONT, (WPARAM)fonts.text, TRUE);
+#endif
+ SetWindowLongPtrW(hwndEditBox, GWLP_USERDATA, (LONG_PTR)dat);
+ SetWindowLongPtrW(hwndEditBox, GWLP_WNDPROC, (LONG_PTR)ReplyEditWndProc);
+ }
+ else {
+ SendMessageA(hwndEditBox, WM_SETFONT, (WPARAM)fonts.text, TRUE);
+ SetWindowLongPtrA(hwndEditBox, GWLP_USERDATA, (LONG_PTR)dat);
+ SetWindowLongPtrA(hwndEditBox, GWLP_WNDPROC, (LONG_PTR)ReplyEditWndProc);
+ }
+ SetFocus(hwndEditBox);
+ break;
+ }
+
+ case ACT_DEF_DETAILS:
+ CallServiceSync(MS_USERINFO_SHOWDIALOG, (WPARAM)m_hContact, 0);
+ if (!(PopUpOptions.actions&ACT_DEF_KEEPWND))
+ PUDeletePopUp(m_hwnd);
+ break;
+ case ACT_DEF_MENU:
+ {
+ lock();
+ PostMessage(ghwndMenuHost, UM_SHOWMENU, (WPARAM)m_hwnd, (LPARAM)m_hContact);
+ break;
+ }
+ case ACT_DEF_ADD:
+ {
+ ADDCONTACTSTRUCT acs = {0};
+ acs.handle = m_hContact;
+ acs.handleType = HANDLE_CONTACT;
+ acs.szProto = 0;
+ CallServiceSync(MS_ADDCONTACT_SHOW, NULL, (LPARAM)&acs);
+ if (!(PopUpOptions.actions&ACT_DEF_KEEPWND))
+ PUDeletePopUp(m_hwnd);
+ break;
+ }
+ case ACT_DEF_PIN:
+ {
+ if (m_bIsPinned)
+ {
+ SetTimer(m_hwnd, POPUP_TIMER, m_iTimeout*1000, NULL);
+ } else
+ {
+ KillTimer(m_hwnd, POPUP_TIMER);
+ }
+ m_bIsPinned = !m_bIsPinned;
+ bool iconSize = PopUpOptions.actions&ACT_LARGE ? TRUE : FALSE;
+ PUModifyActionIcon(m_hwnd, wParam, lParam, m_bIsPinned ? IcoLib_GetIcon(ICO_ACT_PINNED,iconSize) : IcoLib_GetIcon(ICO_ACT_PIN,iconSize));
+ break;
+ }
+ case ACT_DEF_DISMISS:
+ PUDeletePopUp(m_hwnd);
+ break;
+ case ACT_DEF_COPY:
+ {
+ #ifdef UNICODE
+ #define CF_TCHAR CF_UNICODETEXT
+ #else
+ #define CF_TCHAR CF_TEXT
+ #endif
+ HGLOBAL clipbuffer;
+ static TCHAR * buffer, *text;
+ char* sztext;
+ if ((this->m_lpwzText) || (this->m_lpwzTitle))
+ {
+ text = (TCHAR*)mir_alloc((_tcslen(this->m_lpwzText) + _tcslen(this->m_lpwzTitle)+3)*sizeof(TCHAR));
+ mir_sntprintf(text, _tcslen(this->m_lpwzText) + _tcslen(this->m_lpwzTitle)+3, _T("%s\n\n%s"), this->m_lpwzTitle, this->m_lpwzText);
+ }
+ else if ((this->m_lpzText) || (this->m_lpzTitle))
+ {
+ sztext = (char*)mir_alloc((lstrlenA(this->m_lpzText) + lstrlenA(this->m_lpzTitle)+3)*sizeof(char));
+ mir_snprintf(sztext, lstrlenA(this->m_lpzText) + lstrlenA(this->m_lpzTitle)+3, "%s\n\n%s", this->m_lpzTitle, this->m_lpzText);
+ text = mir_a2t(sztext);
+ }
+ OpenClipboard(m_hwnd);
+ EmptyClipboard();
+ clipbuffer = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (lstrlen(text)+1) * sizeof(TCHAR));
+ buffer = (TCHAR *)GlobalLock(clipbuffer);
+ lstrcpy(buffer, text);
+ GlobalUnlock(clipbuffer);
+ SetClipboardData(CF_TCHAR, clipbuffer);
+ CloseClipboard();
+ if (sztext)
+ mir_free(text);
+ PUDeletePopUp(m_hwnd);
+ break;
+ }
+ }
+ break;
+ }
+
+ case UM_POPUPMODIFYACTIONICON:
+ {
+ LPPOPUPACTIONID actionId = (LPPOPUPACTIONID)wParam;
+ for (int i = 0; i < m_actionCount; ++i)
+ if ((m_actions[i].actionA.wParam == actionId->wParam) &&
+ (m_actions[i].actionA.lParam == actionId->lParam))
+ {
+ m_actions[i].actionA.lchIcon = (HICON)lParam;
+ animate();
+ break;
+ }
+
+ break;
+ }
+
+ case UM_MENUDONE:
+ {
+ unlock();
+ if (!(PopUpOptions.actions&ACT_DEF_KEEPWND))
+ PUDeletePopUp(m_hwnd);
+ break;
+ }
+/*
+ case WM_WINDOWPOSCHANGED:
+ {
+ WINDOWPOS *wp = (WINDOWPOS *)lParam;
+ if (!bIsHovered)
+ {
+ RECT rc; SetRect(&rc, wp->x, wp->y, wp->x + wp->cx, wp->y + wp->cy);
+ GetCursorPos(&ptPrevCursor);
+
+ if (PtInRect(&rc, ptPrevCursor))
+ {
+ SetWindowLongPtr(hwnd, GWLP_EXSTYLE, GetWindowLongPtr(hwnd, GWLP_EXSTYLE) | WS_EX_TRANSPARENT);
+ SetTimer(hwnd, CURSOR_TIMER, 500, NULL);
+ }
+ }
+ break;
+ }
+*/
+ case WM_LBUTTONUP:
+ {
+ int i;
+ for (i = 0; i < m_actionCount; ++i)
+ if (m_actions[i].hover)
+ {
+ SendMessage(m_hwnd, UM_POPUPACTION, m_actions[i].actionA.wParam, m_actions[i].actionA.lParam);
+ break;
+ }
+
+ if (i == m_actionCount)
+ {
+ if(PopUpOptions.overrideLeft!=false && (m_hContact!=NULL || PopUpOptions.overrideLeft == 5 || PopUpOptions.overrideLeft == 6)){
+ switch (PopUpOptions.overrideLeft){
+ default:
+ case 1:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_MESSAGE); break;
+ case 2:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_REPLY); break;
+ case 3:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_DETAILS); break;
+ case 4:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_MENU); break;
+ case 5:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_DISMISS); break;
+ case 6:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_PIN); break;
+ case 7:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_COPY); break;
+ }
+ }else{
+ lock();
+ if (!PerformAction(m_hNotification, m_hwnd, message, wParam, lParam))
+ SendMessage(m_hwnd, WM_COMMAND, 0, 0);
+ unlock();
+ }
+ }
+ break;
+ }
+
+ case WM_MBUTTONUP:
+ {
+ if(PopUpOptions.overrideMiddle!=false && (m_hContact!=NULL || PopUpOptions.overrideMiddle == 5 || PopUpOptions.overrideMiddle == 6)){
+ switch (PopUpOptions.overrideMiddle){
+ default:
+ case 1:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_MESSAGE); break;
+ case 2:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_REPLY); break;
+ case 3:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_DETAILS); break;
+ case 4:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_MENU); break;
+ case 5:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_DISMISS); break;
+ case 6:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_PIN); break;
+ case 7:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_COPY); break;
+ }
+ }
+ break;
+ }
+
+ case WM_CONTEXTMENU:
+ {
+ if(PopUpOptions.overrideRight!=false && (m_hContact!=NULL || PopUpOptions.overrideRight == 5 || PopUpOptions.overrideRight == 6)){
+ switch (PopUpOptions.overrideRight){
+ default:
+ case 1:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_MESSAGE); break;
+ case 2:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_REPLY); break;
+ case 3:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_DETAILS); break;
+ case 4:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_MENU); break;
+ case 5:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_DISMISS); break;
+ case 6:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_PIN); break;
+ case 7:SendMessage(m_hwnd, UM_POPUPACTION,0, ACT_DEF_COPY); break;
+ }
+ return TRUE;
+ }else{
+ lock();
+ if (PerformAction(m_hNotification, m_hwnd, message, wParam, lParam))
+ {
+ unlock();
+ return TRUE;
+ }
+ unlock();
+ }
+ }
+/*
+ case WM_RBUTTONUP:
+ {
+ SendMessage(hwnd, WM_CONTEXTMENU, 0, 0);
+ break;
+ }
+*/
+ case WM_TIMER:
+ {
+ switch (wParam)
+ {
+ case POPUP_TIMER:
+ {
+ KillTimer(m_hwnd, POPUP_TIMER);
+ if (!m_customPopup)
+ {
+ PopupThreadRequestRemoveWindow(this);
+ } else
+ {
+ if (isLocked())
+ {
+ updateTimer();
+ } else
+ {
+ PostMessage(m_hwnd, WM_CLOSE, 0, 0);
+ }
+ }
+ break;
+ }
+
+ case AVATAR_TIMER:
+ {
+ int newDelay = m_avatar->activeFrameDelay();
+ animate();
+ if ((newDelay <= 0) || (newDelay != m_avatarFrameDelay)) KillTimer(m_hwnd, AVATAR_TIMER);
+ if (newDelay > 0) {
+ SetTimer(m_hwnd, AVATAR_TIMER, newDelay, 0);
+ m_avatarFrameDelay = newDelay;
+ }
+ break;
+ }
+
+ case CURSOR_TIMER:
+ {
+ POINT pt; GetCursorPos(&pt);
+ if (abs(pt.x-m_ptPrevCursor.x) + abs(pt.y-m_ptPrevCursor.y) > 4)
+ {
+ SetWindowLong(m_hwnd, GWL_EXSTYLE, GetWindowLong(m_hwnd, GWL_EXSTYLE) & ~WS_EX_TRANSPARENT);
+ KillTimer(m_hwnd, CURSOR_TIMER);
+ }
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case UM_DESTROYPOPUP:
+ {
+ KillTimer(m_hwnd, POPUP_TIMER);
+ KillTimer(m_hwnd, AVATAR_TIMER);
+ KillTimer(m_hwnd, CURSOR_TIMER);
+ PostMessage(m_hwnd, WM_CLOSE, 0, 0);
+ break;
+ }
+
+ case UM_CHANGEPOPUP:
+ {
+ switch (wParam)
+ {
+ case CPT_TEXT: updateText((char *)lParam); mir_free((void *)lParam); break;
+ case CPT_TEXTW: updateText((WCHAR *)lParam); mir_free((void *)lParam); break;
+ case CPT_TITLE: updateTitle((char *)lParam); mir_free((void *)lParam); break;
+ case CPT_TITLEW: updateTitle((WCHAR *)lParam); mir_free((void *)lParam); break;
+ case CPT_DATA: updateData((POPUPDATA *)lParam); mir_free((void *)lParam); break;
+ case CPT_DATAEX: updateData((POPUPDATAEX_V2 *)lParam); mir_free((void *)lParam); break;
+ case CPT_DATAW: updateData((POPUPDATAW_V2 *)lParam); mir_free((void *)lParam); break;
+ }
+ update();
+ break;
+ }
+
+ case UM_CALLMETHOD:
+ {
+ MethodPtr *method_copy = (MethodPtr *)wParam;
+ (this->*(*method_copy))(lParam);
+ delete method_copy;
+ break;
+ }
+
+ case WM_PAINT:
+ {
+ if (GetUpdateRect(m_hwnd, 0, FALSE))
+ {
+ PAINTSTRUCT ps;
+ HDC mydc = BeginPaint(m_hwnd, &ps);
+ BitBlt(mydc, 0, 0, m_sz.cx, m_sz.cy, m_bmp->getDC(), 0, 0, SRCCOPY);
+ EndPaint(m_hwnd, &ps);
+ return 0;
+ }
+ break;
+ }
+
+ case WM_PRINT:
+ case WM_PRINTCLIENT:
+ {
+ HDC mydc = (HDC)wParam;
+ BitBlt(mydc, 0, 0, m_sz.cx, m_sz.cy, m_bmp->getDC(), 0, 0, SRCCOPY);
+ break;
+ }
+
+ case WM_MOUSEMOVE:
+ {
+ const PopupSkin *skin = skins.getSkin(m_lpzSkin?m_lpzSkin:m_options->SkinPack);
+ if (skin)
+ if (skin->onMouseMove(this, LOWORD(lParam), HIWORD(lParam)))
+ animate();
+
+ if (m_bIsHovered) break;
+ TRACKMOUSEEVENT tme;
+ tme.cbSize = sizeof(tme);
+ tme.dwFlags = TME_LEAVE;
+ tme.dwHoverTime = HOVER_DEFAULT;
+ tme.hwndTrack = m_hwnd;
+ _TrackMouseEvent(&tme);
+ if (!m_customPopup) PopupThreadLock();
+#if defined(_UNICODE)
+ if (m_options->OpaqueOnHover)
+ updateLayered(255);
+#else
+ if (MySetLayeredWindowAttributes && m_options->OpaqueOnHover)
+ updateLayered(255);
+#endif
+ m_bIsHovered = true;
+ break;
+ }
+ case WM_MOUSELEAVE:
+ {
+ const PopupSkin *skin = skins.getSkin(m_lpzSkin?m_lpzSkin:m_options->SkinPack);
+ if (skin)
+ if (skin->onMouseMove(this, LOWORD(lParam), HIWORD(lParam)))
+ animate();
+
+ if (!m_bIsHovered) break;
+#if defined(_UNICODE)
+ if (m_options->OpaqueOnHover)
+ updateLayered(m_options->UseTransparency ? m_options->Alpha : 255);
+#else
+ if (MySetLayeredWindowAttributes && m_options->OpaqueOnHover)
+ updateLayered(m_options->UseTransparency ? m_options->Alpha : 255);
+#endif
+ if (!m_customPopup) PopupThreadUnlock();
+ m_bIsHovered = false;
+ break;
+ }
+
+ case WM_CLOSE:
+ {
+ hide();
+ return TRUE;
+ }
+
+ case WM_DESTROY:
+ {
+ if (m_bIsHovered)
+ {
+ if (!m_customPopup) PopupThreadUnlock();
+ m_bIsHovered = false;
+ }
+ if (m_hhkAvatarChanged)
+ PopUp_UnhookEventAsync((WPARAM)m_hwnd, (LPARAM)m_hhkAvatarChanged);
+ SendMessage(m_hwnd, UM_FREEPLUGINDATA, 0, 0);
+ SetWindowLongPtr(m_hwnd, GWLP_USERDATA, 0);
+ m_hwnd = 0;
+
+ DestroyWindow(m_hwndToolTip);
+
+ if (!m_customPopup)
+ {
+ // we can't access "this" pointer after followint line!
+ PopupThreadRemoveWindow(this);
+ } else
+ {
+ delete this;
+ }
+
+ PostQuitMessage(0);
+ return TRUE;
+ }
+/*
+ case WM_WINDOWPOSCHANGING:
+// case WM_WINDOWPOSCHANGED:
+ {
+ WINDOWPOS *wp = (WINDOWPOS *)lParam;
+ wp->flags |= SWP_NOACTIVATE; // block focus stealing
+
+ if (!(wp->flags & SWP_NOZORDER))
+ {
+ if ((wp->hwndInsertAfter == HWND_BOTTOM) ||
+ (wp->hwndInsertAfter == HWND_NOTOPMOST) ||
+ (wp->hwndInsertAfter == HWND_TOP))
+ {
+ wp->hwndInsertAfter == HWND_TOPMOST;
+ } else
+ if (wp->hwndInsertAfter != HWND_TOPMOST)
+ {
+ HWND hwndAbove = GetWindow(wp->hwndInsertAfter, GW_HWNDPREV);
+ if (hwndAbove)
+ {
+ char buf[64];
+ GetClassName(hwndAbove, buf, sizeof(buf));
+ buf[sizeof(buf)-1] = 0;
+
+ if (lstrcmp(buf, POPUP_WNDCLASS))
+ wp->hwndInsertAfter == HWND_TOPMOST;
+ }
+ }
+ }
+
+ // this allows us to reduce message traffic
+ return 0;
+ }
+*/
+ }
+
+ if (m_PluginWindowProc && !closing)
+ {
+ lock();
+
+ // some plugins use cdecl instead of stdcall
+ // this is an attempt to fix them
+ BOOL result;
+
+ result = m_PluginWindowProc(this->m_hwnd, message, wParam, lParam);
+/*
+ DWORD esp_in, esp_out, esp_fixed;
+ __asm
+ {
+ push ecx
+ mov [esp_in], esp
+ push [lParam]
+ push [wParam]
+ push [message]
+ mov ecx, [this]
+ push [ecx+hwnd]
+ call [ecx+PluginWindowProc]
+ mov [result], eax
+ mov [esp_out], esp
+ cmp esp, [esp_in] ; check it
+ jz lbl_stack_fix_end
+ pop ecx ; fix stack
+ pop ecx
+ pop ecx
+ pop ecx
+lbl_stack_fix_end: ; end of stack fix hack
+ mov [esp_fixed], esp
+ pop ecx
+ }
+
+#ifndef POPUP_NO_STACK_WARNING
+ if (esp_in != esp_out)
+ {
+ HANDLE hBadModule = 0;
+ char szBadModule[64] = {0};
+
+ // plugin enumeration from the core
+ char exe[MAX_PATH];
+ char search[MAX_PATH];
+ char *p = 0;
+ // get miranda's exe path
+ GetModuleFileNameA(NULL, exe, SIZEOF(exe));
+ // find the last \ and null it out, this leaves no trailing slash
+ p = strrchr(exe, '\\');
+ if ( p ) *p=0;
+ // create the search filter
+ mir_snprintf(search,SIZEOF(search),"%s\\Plugins\\*.dll", exe);
+ {
+ // FFFN will return filenames for things like dot dll+ or dot dllx
+ HANDLE hFind=INVALID_HANDLE_VALUE;
+ WIN32_FIND_DATAA ffd;
+ hFind = FindFirstFileA(search, &ffd);
+ if ( hFind != INVALID_HANDLE_VALUE )
+ {
+ do
+ {
+ if ( !(ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ HMODULE hModule = GetModuleHandleA(ffd.cFileName);
+ if (((char *)PluginWindowProc > (char *)hModule) &&
+ (((char *)PluginWindowProc - (char *)hModule) < ((char *)PluginWindowProc - (char *)hBadModule)))
+ {
+ hBadModule = hModule;
+ lstrcpynA(szBadModule, ffd.cFileName, sizeof(szBadModule));
+ }
+ }
+ } while ( FindNextFileA(hFind, &ffd) );
+ FindClose(hFind);
+ }
+ }
+
+#ifdef POPUP_STACK_WARNING_MSGBOX
+ char buf[256];
+ mir_snprintf(buf, sizeof(buf),
+ "Some plugin passed callback with invalid calling\r\n"
+ "convention and caused stack corruption\r\n"
+ "Module name: %s\r\n"
+ "PluginWindowProc: %x\r\n"
+ "ESP Before: %d\r\n"
+ "ESP After: %d\r\n"
+ "ESP Fixed: %d",
+ szBadModule,
+ PluginWindowProc,
+ esp_in, esp_out, esp_fixed);
+
+ MessageBox(NULL, buf, _T("Popup Plus stack check"), MB_ICONSTOP|MB_OK);
+#else
+ strcat(exe, "\\popup_stack.log");
+ FILE *f = fopen(exe,"a");
+ fprintf(f,
+ "Module name: %s; PluginWindowProc: 0x%x; ESP Before: %d; ESP After: %d; ESP Fixed: %d\n",
+ szBadModule,
+ PluginWindowProc,
+ esp_in, esp_out, esp_fixed);
+ fclose(f);
+#endif // _DEBUG
+ }
+#endif // POPUP_NO_STACK_WARNING
+*/
+ unlock();
+ return result;
+ }
+
+ return NullWindowProc(this->m_hwnd, message, wParam, lParam);
+}
+
+LRESULT CALLBACK PopupWnd2::WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ PopupWnd2 *wnd = 0;
+ if (message == WM_CREATE)
+ {
+ LPCREATESTRUCT cs = (LPCREATESTRUCT)lParam;
+ wnd = (PopupWnd2 *)cs->lpCreateParams;
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)wnd);
+ } else
+ {
+ wnd = (PopupWnd2 *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ }
+ if (wnd) return wnd->WindowProc(message, wParam, lParam);
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+void WindowThread(void *arg)
+{
+ CallService(MS_SYSTEM_THREAD_PUSH, 0, 0);
+ OleInitialize(NULL); // we may need OLE in this thread for smiley substitution
+
+ PopupWnd2 *wnd = (PopupWnd2 *)arg;
+ wnd->buildMText();
+ wnd->create();
+ PostMessage(wnd->getHwnd(), UM_INITPOPUP, 0, 0);
+
+ MSG msg;
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ CallService(MS_SYSTEM_THREAD_POP, 0, 0);
+ _endthread();
+}
+
+// Menu Host
+LRESULT CALLBACK MenuHostWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ static HANDLE hContact = NULL;
+
+ switch (message)
+ {
+ case UM_SHOWMENU:
+ {
+ hContact = (HANDLE)lParam;
+ POINT pt = {0};
+ HMENU hMenu = (HMENU)CallService(MS_CLIST_MENUBUILDCONTACT,(WPARAM)hContact,0);
+ GetCursorPos(&pt);
+ HWND hwndSave = GetForegroundWindow();
+ SetForegroundWindow(hwnd);
+ TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hwnd, NULL);
+ SetForegroundWindow(hwndSave);
+ DestroyMenu(hMenu);
+ PostMessage((HWND)wParam, UM_MENUDONE, 0, 0);
+ break;
+ }
+
+ case WM_COMMAND:
+ {
+ // do not call PluginWindowProc if menu item was clicked. prevent auto-closing...
+ if (CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM)hContact))
+ return DefWindowProc(hwnd, message, wParam, lParam);
+ break;
+ }
+
+ case WM_MEASUREITEM:
+ return CallService(MS_CLIST_MENUMEASUREITEM,wParam,lParam);
+
+ case WM_DRAWITEM:
+ return CallService(MS_CLIST_MENUDRAWITEM,wParam,lParam);
+ }
+
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
|