summaryrefslogtreecommitdiff
path: root/plugins/YAPP/src
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/YAPP/src')
-rw-r--r--plugins/YAPP/src/common.h114
-rw-r--r--plugins/YAPP/src/m_yapp.h29
-rw-r--r--plugins/YAPP/src/message_pump.cpp186
-rw-r--r--plugins/YAPP/src/message_pump.h23
-rw-r--r--plugins/YAPP/src/notify.h7
-rw-r--r--plugins/YAPP/src/notify_imp.cpp146
-rw-r--r--plugins/YAPP/src/options.cpp505
-rw-r--r--plugins/YAPP/src/options.h36
-rw-r--r--plugins/YAPP/src/popwin.cpp772
-rw-r--r--plugins/YAPP/src/popwin.h28
-rw-r--r--plugins/YAPP/src/resource.h79
-rw-r--r--plugins/YAPP/src/services.cpp524
-rw-r--r--plugins/YAPP/src/services.h10
-rw-r--r--plugins/YAPP/src/version.h24
-rw-r--r--plugins/YAPP/src/yapp.cpp241
-rw-r--r--plugins/YAPP/src/yapp.h12
-rw-r--r--plugins/YAPP/src/yapp_history.cpp87
-rw-r--r--plugins/YAPP/src/yapp_history.h96
-rw-r--r--plugins/YAPP/src/yapp_history_dlg.cpp743
19 files changed, 3662 insertions, 0 deletions
diff --git a/plugins/YAPP/src/common.h b/plugins/YAPP/src/common.h
new file mode 100644
index 0000000000..1b2a52b74b
--- /dev/null
+++ b/plugins/YAPP/src/common.h
@@ -0,0 +1,114 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#define _CRT_SECURE_NO_WARNINGS
+
+// Modify the following defines if you have to target a platform prior to the ones specified below.
+// Refer to MSDN for the latest info on corresponding values for different platforms.
+#ifndef WINVER // Allow use of features specific to Windows XP or later.
+#define WINVER 0x0501 // Change this to the appropriate value to target other versions of Windows.
+#endif
+
+#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
+#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
+#endif
+
+#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later.
+#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
+#endif
+
+#ifndef _WIN32_IE // Allow use of features specific to IE 6.0 or later.
+#define _WIN32_IE 0x0600 // Change this to the appropriate value to target other versions of IE.
+#endif
+
+
+#include <m_stdhdr.h>
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files:
+#include <windows.h>
+#include <commctrl.h>
+#include <time.h>
+
+#define MIRANDA_VER 0x0A00
+
+#include <newpluginapi.h>
+#include <statusmodes.h>
+#include <m_database.h>
+#include <m_langpack.h>
+#include <m_options.h>
+#include <m_system.h>
+#include <m_system_cpp.h>
+#include <m_idle.h>
+#include <m_skin.h>
+#include <m_clui.h>
+#include <m_clist.h>
+#include <m_utils.h>
+#include <m_fontservice.h>
+#include <m_avatars.h>
+#include <m_popup.h>
+#include <win2k.h>
+
+#include <m_notify.h>
+
+#define MODULE "YAPP"
+
+extern HMODULE hInst;
+
+extern HFONT hFontFirstLine, hFontSecondLine, hFontTime;
+extern COLORREF colFirstLine, colSecondLine, colBg, colTime, colBorder, colSidebar, colTitleUnderline;
+
+extern MNOTIFYLINK *notifyLink;
+
+// work around a bug in neweventnotify, possibly httpserver
+// ignore the address passed to the 'get plugin data' service
+extern bool ignore_gpd_passed_addy;
+
+// win32 defines for mingw version of windows headers :(
+#ifndef LVM_SORTITEMSEX
+#define LVM_SORTITEMSEX (LVM_FIRST + 81)
+
+typedef int (CALLBACK *PFNLVCOMPARE)(LPARAM, LPARAM, LPARAM);
+
+#define ListView_SortItemsEx(hwndLV, _pfnCompare, _lPrm) \
+ (BOOL)SendMessage((hwndLV), LVM_SORTITEMSEX, (WPARAM)(LPARAM)(_lPrm), (LPARAM)(PFNLVCOMPARE)(_pfnCompare))
+#endif
+
+
+typedef struct {
+ int cbSize;
+ int flags; // OR of PDF_* flags below
+ HANDLE hContact;
+ HICON hIcon;
+ union {
+ char *pszTitle;
+ TCHAR *ptzTitle;
+ wchar_t *pwzTitle;
+ };
+ union {
+ char *pszText;
+ TCHAR *ptzText;
+ wchar_t *pwzText;
+ };
+ COLORREF colorBack; // if colorBack and colorText are equal, defaults will be used
+ COLORREF colorText;
+ WNDPROC windowProc; // optional custom window procedure
+ int timeout; // -1 == infinite, 0 == default, otherwise timeout in seconds
+ void *opaque;
+} PopupData;
+
+#define PDF_UNICODE 0x0001
+
+#define PDF_TCHAR PDF_UNICODE
+
+// windowProc messages
+#define PM_INIT (WM_USER + 0x0202) // message sent to your windowProc after the window has been initialized
+#define PM_DIENOTIFY (WM_USER + 0x0200) // message sent to your windowProc just before the window is destroyed (can be used e.g. to free your opaque data)
+
+#define PM_DESTROY (WM_USER + 0x0201) // send to the popup hWnd (use PostMessage generally, or SendMessage inside your windowProc) to kill it
+
+void ShowPopup(PopupData &pd_in); \ No newline at end of file
diff --git a/plugins/YAPP/src/m_yapp.h b/plugins/YAPP/src/m_yapp.h
new file mode 100644
index 0000000000..26d9be0e2e
--- /dev/null
+++ b/plugins/YAPP/src/m_yapp.h
@@ -0,0 +1,29 @@
+#ifndef __m_yapp_h__
+#define __m_yapp_h__
+
+#define NFOPT_POPUP2_BACKCOLOR "Popup2/BackColor"
+#define NFOPT_POPUP2_TEXTCOLOR "Popup2/TextColor"
+#define NFOPT_POPUP2_TIMEOUT "Popup2/Timeout"
+#define NFOPT_POPUP2_LCLICKSVC "Popup2/LClickSvc"
+#define NFOPT_POPUP2_LCLICKCOOKIE "Popup2/LClickCookie"
+#define NFOPT_POPUP2_RCLICKSVC "Popup2/RClickSvc"
+#define NFOPT_POPUP2_RCLICKCOOKIE "Popup2/RClickCookie"
+#define NFOPT_POPUP2_STATUSMODE "Popup2/StatusMode"
+#define NFOPT_POPUP2_PLUGINDATA "Popup2/PluginData"
+#define NFOPT_POPUP2_WNDPROC "Popup2/WndProc"
+
+#define NFOPT_POPUP2_BACKCOLOR_S "Popup2/BackColor/Save"
+#define NFOPT_POPUP2_TEXTCOLOR_S "Popup2/TextColor/Save"
+#define NFOPT_POPUP2_TIMEOUT_S "Popup2/Timeout/Save"
+
+#define MS_POPUP2_SHOW "Popup2/Show"
+#define MS_POPUP2_UPDATE "Popup2/Update"
+#define MS_POPUP2_REMOVE "Popup2/Remove"
+
+#ifndef POPUP2_NOHELPERS
+ #define MPopup2Show(a) (CallService(MS_POPUP2_SHOW, 0, (LPARAM)(a)))
+ #define MPopup2Update(a) (CallService(MS_POPUP2_UPDATE, 0, (LPARAM)(a)))
+ #define MPopup2Remove(a) (CallService(MS_POPUP2_REMOVE, 0, (LPARAM)(a)))
+#endif
+
+#endif // __m_yapp_h__
diff --git a/plugins/YAPP/src/message_pump.cpp b/plugins/YAPP/src/message_pump.cpp
new file mode 100644
index 0000000000..7e2cea5f0c
--- /dev/null
+++ b/plugins/YAPP/src/message_pump.cpp
@@ -0,0 +1,186 @@
+#include "common.h"
+#include "message_pump.h"
+#include "popwin.h"
+#include "services.h"
+#include "options.h"
+
+unsigned message_pump_thread_id = 0;
+int num_popups = 0;
+
+HANDLE hMPEvent;
+
+#define MUM_FINDWINDOW (WM_USER + 0x050)
+
+#define MAX_POPUPS 100
+
+// from popups, popup2 implementation, slightly modified
+// return true if there is a full-screen application (e.g. game) running
+bool is_full_screen() {
+ int w = GetSystemMetrics(SM_CXSCREEN);
+ int h = GetSystemMetrics(SM_CYSCREEN);
+ // use ClientRect instead of WindowRect so that it works normally for maximized applications - thx Nikto
+ RECT ClientRect;
+ HWND hWnd;
+
+ HWND hWndDesktop = GetDesktopWindow();
+ HWND hWndShell = GetShellWindow();
+
+ // check foregroundwindow
+ hWnd = GetForegroundWindow();
+ if(hWnd && hWnd != hWndDesktop && hWnd != hWndShell) {
+ GetClientRect(hWnd, &ClientRect);
+ if ((ClientRect.right - ClientRect.left) >= w && (ClientRect.bottom - ClientRect.top) >= h)
+ return true;
+ }
+
+ // check other top level windows
+ while ((hWnd = FindWindowEx(NULL, hWnd, NULL, NULL))) {
+ if(IsWindowVisible(hWnd) == 0 || IsIconic(hWnd) || hWnd == hWndDesktop || hWnd == hWndShell)
+ continue;
+
+// if(DBGetContactSettingByte(0, MODULE, "ShowForNonTopmostFullscreenWindows", 0) == 1) {
+ if (!(GetWindowLongPtr(hWnd, GWL_EXSTYLE) & WS_EX_TOPMOST))
+ continue;
+// }
+
+ // not sure if this could be done more simply using 'IsZoomed'?
+ GetClientRect(hWnd, &ClientRect);
+ if ((ClientRect.right - ClientRect.left) < w || (ClientRect.bottom - ClientRect.top) < h)
+ continue;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool is_workstation_locked()
+{
+ bool rc = false;
+ HDESK hDesk = OpenDesktop((TCHAR*)_T("default"), 0, FALSE, DESKTOP_SWITCHDESKTOP);
+ if(hDesk != 0) {
+ HDESK hDeskInput = OpenInputDesktop(0, FALSE, DESKTOP_SWITCHDESKTOP);
+ if(hDeskInput == 0) {
+ rc = true;
+ } else
+ CloseDesktop(hDeskInput);
+
+ CloseDesktop(hDesk);
+ }
+
+ return rc;
+}
+
+
+unsigned __stdcall MessagePumpThread(void* param)
+{
+ InitWindowStack();
+
+ if(param) SetEvent((HANDLE)param);
+
+ MSG hwndMsg = {0};
+ while(GetMessage(&hwndMsg, 0, 0, 0) > 0 && !Miranda_Terminated()) {
+ if (!IsDialogMessage(hwndMsg.hwnd, &hwndMsg)) {
+ switch(hwndMsg.message) {
+ case MUM_CREATEPOPUP:
+ {
+ bool enabled = true;
+ int status = CallService(MS_CLIST_GETSTATUSMODE, 0, 0);
+ if(status >= ID_STATUS_OFFLINE && status <= ID_STATUS_OUTTOLUNCH && options.disable_status[status - ID_STATUS_OFFLINE])
+ enabled = false;
+ if ((options.disable_full_screen && is_full_screen()) || is_workstation_locked())
+ enabled = false;
+
+ PopupData *pd = (PopupData *)hwndMsg.lParam;
+ if(enabled && num_popups < MAX_POPUPS) {
+ //HWND hwnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TOPMOST, POP_WIN_CLASS, _T("Popup"), WS_POPUP, 0, 0, 0, 0, GetDesktopWindow(), 0, hInst, (LPVOID)hwndMsg.lParam);
+ HWND hwnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TOPMOST, POP_WIN_CLASS, _T("Popup"), WS_POPUP, 0, 0, 0, 0, 0, 0, hInst, (LPVOID)hwndMsg.lParam);
+ num_popups++;
+ if(hwndMsg.wParam) // set notifyer handle
+ SendMessage(hwnd, PUM_SETNOTIFYH, hwndMsg.wParam, 0);
+ } else {
+ if (pd) {
+ mir_free(pd->pwzTitle);
+ mir_free(pd->pwzText);
+ mir_free(pd);
+ }
+ }
+ }
+ break;
+
+ case MUM_DELETEPOPUP:
+ {
+ HWND hwnd = (HWND)hwndMsg.lParam;
+ if(IsWindow(hwnd)) {
+ DestroyWindow(hwnd);
+ num_popups--;
+ }
+ }
+ break;
+
+ case MUM_NMUPDATE:
+ {
+ HANDLE hNotify = (HANDLE)hwndMsg.wParam;
+ BroadcastMessage(PUM_UPDATENOTIFY, (WPARAM)hNotify, 0);
+ }
+ break;
+
+ case MUM_NMREMOVE:
+ {
+ HANDLE hNotify = (HANDLE)hwndMsg.wParam;
+ BroadcastMessage(PUM_KILLNOTIFY, (WPARAM)hNotify, 0);
+ }
+ break;
+
+ case MUM_NMAVATAR:
+ RepositionWindows();
+ break;
+
+ default:
+ TranslateMessage(&hwndMsg);
+ DispatchMessage(&hwndMsg);
+ break;
+ }
+ }
+ }
+
+ DeinitWindowStack();
+ num_popups = 0;
+
+ //if(param) SetEvent((HANDLE)param);
+
+ DeinitOptions();
+ DeinitServices();
+
+ return 0;
+}
+
+void PostMPMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+ PostThreadMessage(message_pump_thread_id, msg, wParam, lParam);
+}
+
+// given a popup data pointer, and a handle to an event, this function
+// will post a message to the message queue which will set the hwnd value
+// and then set the event...so create an event, call this function and then wait on the event
+// when the event is signalled, the hwnd will be valid
+void FindWindow(PopupData *pd, HANDLE hEvent, HWND *hwnd);
+
+void InitMessagePump() {
+ WNDCLASS popup_win_class = {0};
+ popup_win_class.lpfnWndProc = PopupWindowProc;
+ popup_win_class.hInstance = hInst;
+ popup_win_class.lpszClassName = POP_WIN_CLASS;
+ popup_win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
+ RegisterClass(&popup_win_class);
+
+ InitServices();
+
+ hMPEvent = CreateEvent(0, TRUE, 0, 0);
+ CloseHandle(mir_forkthreadex(MessagePumpThread, hMPEvent, &message_pump_thread_id));
+ WaitForSingleObject(hMPEvent, INFINITE);
+ CloseHandle(hMPEvent);
+}
+
+void DeinitMessagePump() {
+ PostMPMessage(WM_QUIT, 0, 0);
+}
diff --git a/plugins/YAPP/src/message_pump.h b/plugins/YAPP/src/message_pump.h
new file mode 100644
index 0000000000..70671b157a
--- /dev/null
+++ b/plugins/YAPP/src/message_pump.h
@@ -0,0 +1,23 @@
+#ifndef _MESSAGE_PUMP_INC
+#define _MESSAGE_PUMP_INC
+
+extern unsigned message_pump_thread_id;
+void PostMPMessage(UINT msg, WPARAM, LPARAM);
+
+#define MUM_CREATEPOPUP (WM_USER + 0x011)
+#define MUM_DELETEPOPUP (WM_USER + 0x012)
+
+#define MUM_NMUPDATE (WM_USER + 0x013)
+#define MUM_NMREMOVE (WM_USER + 0x014)
+#define MUM_NMAVATAR (WM_USER + 0x015)
+
+// given a popup data pointer, and a handle to an event, this function
+// will post a message to the message queue which will set the hwnd value
+// and then set the event...so create an event, call this function and then wait on the event
+// when the event is signalled, the hwnd will be valid
+void FindWindow(PopupData *pd, HANDLE hEvent, HWND *hwnd);
+
+void InitMessagePump();
+void DeinitMessagePump();
+
+#endif
diff --git a/plugins/YAPP/src/notify.h b/plugins/YAPP/src/notify.h
new file mode 100644
index 0000000000..7f39eb6d65
--- /dev/null
+++ b/plugins/YAPP/src/notify.h
@@ -0,0 +1,7 @@
+#ifndef _NOTIFY_IMP_INC
+#define _NOTIFY_IMP_INC
+
+void InitNotify();
+void DeinitNotify();
+
+#endif
diff --git a/plugins/YAPP/src/notify_imp.cpp b/plugins/YAPP/src/notify_imp.cpp
new file mode 100644
index 0000000000..061c30f1a2
--- /dev/null
+++ b/plugins/YAPP/src/notify_imp.cpp
@@ -0,0 +1,146 @@
+#include "common.h"
+#include "resource.h"
+#include "notify.h"
+#include "message_pump.h"
+#include "m_yapp.h"
+
+HANDLE hhkShow=0, hhkUpdate=0, hhkRemove=0;
+
+//struct
+
+int Popup2Show(WPARAM wParam, LPARAM lParam) {
+
+ HANDLE hNotify = (HANDLE)lParam;
+
+ PopupData *pd_out = (PopupData *)mir_alloc(sizeof(PopupData));
+ memset(pd_out, 0, sizeof(PopupData));
+
+ PostMPMessage(MUM_CREATEPOPUP, (WPARAM)hNotify, (LPARAM)pd_out);
+ PostMPMessage(MUM_NMUPDATE, (WPARAM)hNotify, (LPARAM)0);
+ return 0;
+}
+
+INT_PTR svcPopup2Show(WPARAM wParam, LPARAM lParam) {
+ return Popup2Show(wParam, lParam);
+}
+
+int Popup2Update(WPARAM wParam, LPARAM lParam) {
+ HANDLE hNotify = (HANDLE)lParam;
+ PostMPMessage(MUM_NMUPDATE, (WPARAM)hNotify, (LPARAM)0);
+ return 0;
+}
+
+int AvatarChanged(WPARAM wParam, LPARAM lParam) {
+ PostMPMessage(MUM_NMAVATAR, (WPARAM)0, (LPARAM)0);
+ return 0;
+}
+
+
+INT_PTR svcPopup2Update(WPARAM wParam, LPARAM lParam) {
+ return Popup2Update(wParam, lParam);
+}
+
+int Popup2Remove(WPARAM wParam, LPARAM lParam) {
+ HANDLE hNotify = (HANDLE)lParam;
+ PostMPMessage(MUM_NMREMOVE, (WPARAM)hNotify, (LPARAM)0);
+ return 0;
+}
+
+INT_PTR svcPopup2Remove(WPARAM wParam, LPARAM lParam) {
+ return Popup2Remove(wParam, lParam);
+}
+
+INT_PTR svcPopup2DefaultActions(WPARAM wParam, LPARAM lParam)
+{
+ //PopupWindow *wnd = (PopupWindow *)MNotifyGetDWord((HANDLE)lParam, "Popup2/data", (DWORD)NULL);
+ //if (!wnd) return 0;
+ switch (wParam)
+ {
+ case 0:
+ { // send message
+ //if (wnd->lchContact) CallServiceSync(MS_MSG_SENDMESSAGE, (WPARAM)wnd->lchContact, 0);
+ //SendMessage(wnd->lchMain, UM_DESTROYPOPUP, 0, 0);
+ break;
+ }
+ case 1:
+ { // dismiss popup
+ //SendMessage(wnd->lchMain, UM_DESTROYPOPUP, 0, 0);
+ break;
+ }
+ }
+ return 0;
+}
+
+INT_PTR CALLBACK DlgProcPopUps(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+/* To change options use MNotifySet*(hNotify, ....) Apply/Cancel is implemented in notify.dll */
+ HANDLE hNotify = (HANDLE)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ switch (msg)
+ {
+ case WM_USER+100:
+ {
+ // This will be extendet to handle array of handles for multiselect lParam
+ // will be HANDLE * and wParam wil; store amount of handles passed
+ hNotify = (HANDLE)lParam;
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+ // This in different from Miranda options!
+ SendMessage(GetParent(GetParent(hwnd)), PSM_CHANGED, 0, 0);
+ break;
+ }
+ return FALSE;
+}
+
+int NotifyOptionsInitialize(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = {0};
+ odp.cbSize = sizeof(odp);
+ odp.hInstance = hInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_NOTIFY);
+ odp.pszTitle = LPGEN("YAPP Popups");
+ odp.flags=ODPF_BOLDGROUPS;
+ odp.pfnDlgProc = DlgProcPopUps;
+ CallService(MS_NOTIFY_OPT_ADDPAGE, wParam, (LPARAM)&odp);
+ return 0;
+}
+
+HANDLE hEventNotifyOptInit, hEventNotifyModulesLoaded;
+HANDLE hAvChangeEvent;
+
+int NotifyModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ hEventNotifyOptInit = HookEvent(ME_NOTIFY_OPT_INITIALISE, NotifyOptionsInitialize);
+ hAvChangeEvent = HookEvent(ME_AV_AVATARCHANGED, AvatarChanged);
+ return 0;
+}
+
+HANDLE hServicesNotify[4];
+void InitNotify() {
+ hhkShow = HookEvent(ME_NOTIFY_SHOW, Popup2Show);
+ hhkUpdate = HookEvent(ME_NOTIFY_UPDATE, Popup2Update);
+ hhkRemove = HookEvent(ME_NOTIFY_REMOVE, Popup2Remove);
+
+ hServicesNotify[0] = CreateServiceFunction("Popup2/DefaultActions", svcPopup2DefaultActions);
+
+ hServicesNotify[1] = CreateServiceFunction(MS_POPUP2_SHOW, svcPopup2Show);
+ hServicesNotify[2] = CreateServiceFunction(MS_POPUP2_UPDATE, svcPopup2Update);
+ hServicesNotify[3] = CreateServiceFunction(MS_POPUP2_REMOVE, svcPopup2Remove);
+
+ hEventNotifyModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, NotifyModulesLoaded);
+}
+
+void DeinitNotify() {
+ UnhookEvent(hhkShow);
+ UnhookEvent(hhkUpdate);
+ UnhookEvent(hhkRemove);
+
+ UnhookEvent(hAvChangeEvent);
+ UnhookEvent(hEventNotifyOptInit);
+ UnhookEvent(hEventNotifyModulesLoaded);
+
+ for(int i = 0; i < 4; i++)
+ DestroyServiceFunction(hServicesNotify[i]);
+}
diff --git a/plugins/YAPP/src/options.cpp b/plugins/YAPP/src/options.cpp
new file mode 100644
index 0000000000..7ba798e5fa
--- /dev/null
+++ b/plugins/YAPP/src/options.cpp
@@ -0,0 +1,505 @@
+#include "common.h"
+#include "options.h"
+#include "resource.h"
+#include "popwin.h"
+#include "services.h"
+
+Options options;
+
+HICON hPopupIcon = 0;
+
+void LoadModuleDependentOptions() {
+ if(ServiceExists(MS_AV_DRAWAVATAR))
+ options.av_layout = (PopupAvLayout)DBGetContactSettingByte(0, MODULE, "AVLayout", PAV_RIGHT);
+ else
+ options.av_layout = PAV_NONE;
+
+ options.time_layout = (PopupTimeLayout)DBGetContactSettingByte(0, MODULE, "TimeLayout", (ServiceExists(MS_AV_DRAWAVATAR) ? PT_WITHAV : PT_RIGHT));
+ if(options.time_layout == PT_WITHAV && !ServiceExists(MS_AV_DRAWAVATAR))
+ options.time_layout = PT_RIGHT;
+}
+
+void LoadOptions() {
+ options.default_timeout = DBGetContactSettingDword(0, MODULE, "DefaultTimeout", 7);
+ options.win_width = DBGetContactSettingDword(0, MODULE, "WinWidth", 220);
+ options.win_max_height = DBGetContactSettingDword(0, MODULE, "WinMaxHeight", 400);
+ options.location = (PopupLocation)DBGetContactSettingByte(0, MODULE, "Location", (BYTE)PL_BOTTOMRIGHT);
+ options.opacity = DBGetContactSettingByte(0, MODULE, "Opacity", 75);
+ options.border = (DBGetContactSettingByte(0, MODULE, "Border", 1) == 1);
+ options.round = (DBGetContactSettingByte(0, MODULE, "RoundCorners", 1) == 1);
+ options.av_round = (DBGetContactSettingByte(0, MODULE, "AvatarRoundCorners", 1) == 1);
+ options.animate = (DBGetContactSettingByte(0, MODULE, "Animate", 1) == 1);
+ options.trans_bg = (DBGetContactSettingByte(0, MODULE, "TransparentBg", 0) == 1);
+ options.use_mim_monitor = (DBGetContactSettingByte(0, MODULE, "UseMimMonitor", 1) == 1);
+ options.right_icon = (DBGetContactSettingByte(0, MODULE, "RightIcon", 0) == 1);
+ options.av_layout = PAV_NONE; // corrected in LoadModuleDependentOptions function above
+ options.av_size = DBGetContactSettingDword(0, MODULE, "AVSize", 40); //tweety
+ options.text_indent = DBGetContactSettingDword(0, MODULE, "TextIndent", 22);
+ options.global_hover = (DBGetContactSettingByte(0, MODULE, "GlobalHover", 1) == 1);
+ options.time_layout = PT_RIGHT; // corrected in LoadModuleDependentOptions function above
+
+ char buff[128];
+ for(int i = 0; i < 10; i++) {
+ sprintf(buff, "DisableStatus%d", i - 1); // -1 because i forgot offline status earlier!
+ options.disable_status[i] = (DBGetContactSettingByte(0, MODULE, buff, 0) == 1);
+ }
+
+ options.disable_full_screen = (DBGetContactSettingByte(0, MODULE, "DisableFullScreen", 1) == 1);
+ options.drop_shadow = (DBGetContactSettingByte(0, MODULE, "DropShadow", 0) == 1);
+ options.sb_width = DBGetContactSettingDword(0, MODULE, "SidebarWidth", 22);
+ options.padding = DBGetContactSettingDword(0, MODULE, "Padding", 4);
+ options.av_padding = DBGetContactSettingDword(0, MODULE, "AvatarPadding", 4);
+}
+
+void SaveOptions() {
+ DBWriteContactSettingDword(0, MODULE, "DefaultTimeout", options.default_timeout);
+ DBWriteContactSettingDword(0, MODULE, "WinWidth", options.win_width);
+ DBWriteContactSettingDword(0, MODULE, "WinMaxHeight", options.win_max_height);
+ DBWriteContactSettingByte(0, MODULE, "Location", (BYTE)options.location);
+ DBWriteContactSettingByte(0, MODULE, "Opacity", (BYTE)options.opacity);
+ DBWriteContactSettingByte(0, MODULE, "Border", (options.border ? 1 : 0));
+ DBWriteContactSettingByte(0, MODULE, "RoundCorners", (options.round ? 1 : 0));
+ DBWriteContactSettingByte(0, MODULE, "AvatarRoundCorners", (options.av_round ? 1 : 0));
+ DBWriteContactSettingByte(0, MODULE, "Animate", (options.animate ? 1 : 0));
+ DBWriteContactSettingByte(0, MODULE, "TransparentBg", (options.trans_bg ? 1 : 0));
+ DBWriteContactSettingByte(0, MODULE, "UseMimMonitor", (options.use_mim_monitor ? 1 : 0));
+ DBWriteContactSettingByte(0, MODULE, "RightIcon", (options.right_icon ? 1 : 0));
+ if(ServiceExists(MS_AV_DRAWAVATAR))
+ DBWriteContactSettingByte(0, MODULE, "AVLayout", (BYTE)options.av_layout);
+ DBWriteContactSettingDword(0, MODULE, "AVSize", options.av_size);
+ DBWriteContactSettingDword(0, MODULE, "TextIndent", options.text_indent);
+ DBWriteContactSettingByte(0, MODULE, "GlobalHover", (options.global_hover ? 1 : 0));
+ DBWriteContactSettingByte(0, MODULE, "TimeLayout", (BYTE)options.time_layout);
+
+ char buff[128];
+ for(int i = 0; i < 9; i++) {
+ sprintf(buff, "DisableStatus%d", i - 1);
+ DBWriteContactSettingByte(0, MODULE, buff, options.disable_status[i] ? 1 : 0);
+ }
+ DBWriteContactSettingByte(0, MODULE, "DisableFullScreen", (options.disable_full_screen ? 1 : 0));
+ DBWriteContactSettingByte(0, MODULE, "DropShadow", (options.drop_shadow ? 1 : 0));
+ DBWriteContactSettingDword(0, MODULE, "SidebarWidth", options.sb_width);
+ DBWriteContactSettingDword(0, MODULE, "Padding", options.padding);
+ DBWriteContactSettingDword(0, MODULE, "AvatarPadding", options.av_padding);
+}
+
+void ShowExamplePopups() {
+ PopupData pd = {sizeof(PopupData)};
+ pd.hIcon = hPopupIcon;
+ pd.flags = PDF_TCHAR;
+
+ pd.ptzTitle = TranslateT("Example");
+ pd.ptzText = TranslateT("The quick brown fox jumped over the lazy dog.");
+ ShowPopup(pd);
+
+ pd.ptzTitle = TranslateT("Example With a Long Title");
+ pd.ptzText = TranslateT("The quick brown fox jumped over the lazy dog.");
+ ShowPopup(pd);
+
+ pd.ptzTitle = TranslateT("Example");
+ pd.ptzText = TranslateT("Thequickbrownfoxjumpedoverthelazydog.");
+ ShowPopup(pd);
+
+ HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while(hContact) {
+ if(options.av_layout != PAV_NONE && ServiceExists(MS_AV_DRAWAVATAR)) {
+ AVATARCACHEENTRY *ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)hContact, 0);
+ if(ace && (ace->dwFlags & AVS_BITMAP_VALID)) {
+ pd.hContact = hContact;
+ pd.ptzText = TranslateT("An avatar.");
+ ShowPopup(pd);
+ break;
+ }
+ }
+
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0);
+ }
+}
+
+static INT_PTR CALLBACK DlgProcOpts1(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+
+ SendDlgItemMessage(hwndDlg, IDC_CMB_PLACEMENT, CB_ADDSTRING, 0, (LPARAM)TranslateT("Bottom right"));
+ SendDlgItemMessage(hwndDlg, IDC_CMB_PLACEMENT, CB_ADDSTRING, 0, (LPARAM)TranslateT("Bottom left"));
+ SendDlgItemMessage(hwndDlg, IDC_CMB_PLACEMENT, CB_ADDSTRING, 0, (LPARAM)TranslateT("Top right"));
+ SendDlgItemMessage(hwndDlg, IDC_CMB_PLACEMENT, CB_ADDSTRING, 0, (LPARAM)TranslateT("Top left"));
+ SendDlgItemMessage(hwndDlg, IDC_CMB_PLACEMENT, CB_SETCURSEL, (int)options.location, 0);
+
+ SendDlgItemMessage(hwndDlg, IDC_CMB_ICON, CB_ADDSTRING, 0, (LPARAM)TranslateT("Icon on left"));
+ SendDlgItemMessage(hwndDlg, IDC_CMB_ICON, CB_ADDSTRING, 0, (LPARAM)TranslateT("Icon on right"));
+ SendDlgItemMessage(hwndDlg, IDC_CMB_ICON, CB_SETCURSEL, (options.right_icon ? 1 : 0), 0);
+
+ SendDlgItemMessage(hwndDlg, IDC_CMB_TIME, CB_ADDSTRING, 0, (LPARAM)TranslateT("No time"));
+ SendDlgItemMessage(hwndDlg, IDC_CMB_TIME, CB_ADDSTRING, 0, (LPARAM)TranslateT("Time on left"));
+ SendDlgItemMessage(hwndDlg, IDC_CMB_TIME, CB_ADDSTRING, 0, (LPARAM)TranslateT("Time on right"));
+ if(ServiceExists(MS_AV_DRAWAVATAR))
+ SendDlgItemMessage(hwndDlg, IDC_CMB_TIME, CB_ADDSTRING, 0, (LPARAM)TranslateT("Time above avatar"));
+ SendDlgItemMessage(hwndDlg, IDC_CMB_TIME, CB_SETCURSEL, (int)options.time_layout, 0);
+
+ SendDlgItemMessage(hwndDlg, IDC_CMB_AV, CB_ADDSTRING, 0, (LPARAM)TranslateT("No avatar"));
+ if(ServiceExists(MS_AV_DRAWAVATAR)) {
+ SendDlgItemMessage(hwndDlg, IDC_CMB_AV, CB_ADDSTRING, 0, (LPARAM)TranslateT("Left avatar"));
+ SendDlgItemMessage(hwndDlg, IDC_CMB_AV, CB_ADDSTRING, 0, (LPARAM)TranslateT("Right avatar"));
+ } else {
+ HWND hw = GetDlgItem(hwndDlg, IDC_CMB_AV);
+ EnableWindow(hw, FALSE);
+ hw = GetDlgItem(hwndDlg, IDC_SPIN_AVSIZE);
+ EnableWindow(hw, FALSE);
+ hw = GetDlgItem(hwndDlg, IDC_ED_AVSIZE);
+ EnableWindow(hw, FALSE);
+ }
+ SendDlgItemMessage(hwndDlg, IDC_CMB_AV, CB_SETCURSEL, (int)options.av_layout, 0);
+
+ CheckDlgButton(hwndDlg, IDC_CHK_GLOBALHOVER, options.global_hover ? TRUE : FALSE);
+
+ {
+ // initialise and fill listbox
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_LST_STATUS);
+ ListView_DeleteAllItems(hwndList);
+
+ SendMessage(hwndList,LVM_SETEXTENDEDLISTVIEWSTYLE, 0,LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES);
+
+ LVCOLUMN lvc = {0};
+ // Initialize the LVCOLUMN structure.
+ // The mask specifies that the format, width, text, and
+ // subitem members of the structure are valid.
+ lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
+ lvc.fmt = LVCFMT_LEFT;
+
+ lvc.iSubItem = 0;
+ lvc.pszText = TranslateT("Status");
+ lvc.cx = 200; // width of column in pixels
+ ListView_InsertColumn(hwndList, 0, &lvc);
+
+
+ LVITEM lvI = {0};
+
+ // Some code to create the list-view control.
+ // Initialize LVITEM members that are common to all
+ // items.
+ lvI.mask = LVIF_TEXT;
+
+ char *strptr;
+ int i = 0;
+ for (; i < 10; i++) {
+ strptr = (char *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM)(ID_STATUS_OFFLINE + i), (LPARAM)0);
+ lvI.pszText = mir_a2t(strptr);
+ lvI.iItem = i;
+ ListView_InsertItem(hwndList, &lvI);
+ ListView_SetCheckState(hwndList, i, options.disable_status[i]);
+ mir_free(lvI.pszText);
+ }
+ lvI.pszText = TranslateT("Full-screen app running");
+ lvI.iItem = i;
+ ListView_InsertItem(hwndList, &lvI);
+ ListView_SetCheckState(hwndList, i, options.disable_full_screen);
+ }
+
+ SendDlgItemMessage(hwndDlg, IDC_SPIN_TIMEOUT, UDM_SETRANGE, 0, (LPARAM)MAKELONG(360, 1));
+ SendDlgItemMessage(hwndDlg, IDC_SPIN_WIDTH, UDM_SETRANGE, 0, (LPARAM)MAKELONG(2048, 16));
+ SendDlgItemMessage(hwndDlg, IDC_SPIN_MAXHEIGHT, UDM_SETRANGE, 0, (LPARAM)MAKELONG(2048, 16));
+ SendDlgItemMessage(hwndDlg, IDC_SPIN_TRANS, UDM_SETRANGE, 0, (LPARAM)MAKELONG(100, 1));
+ SendDlgItemMessage(hwndDlg, IDC_SPIN_AVSIZE, UDM_SETRANGE, 0, (LPARAM)MAKELONG(100, 16));
+ SendDlgItemMessage(hwndDlg, IDC_SPIN_INDENT, UDM_SETRANGE, 0, (LPARAM)MAKELONG(400, 0));
+ SendDlgItemMessage(hwndDlg, IDC_SPIN_SBWIDTH, UDM_SETRANGE, 0, (LPARAM)MAKELONG(2048, 0));
+ SendDlgItemMessage(hwndDlg, IDC_SPIN_PADDING, UDM_SETRANGE, 0, (LPARAM)MAKELONG(400, 0));
+
+ if(options.default_timeout == -1) {
+ CheckDlgButton(hwndDlg, IDC_RAD_NOTIMEOUT, TRUE);
+ HWND hw = GetDlgItem(hwndDlg, IDC_ED_TIMEOUT);
+ EnableWindow(hw, FALSE);
+ SetDlgItemInt(hwndDlg, IDC_ED_TIMEOUT, 7, FALSE);
+ } else {
+ CheckDlgButton(hwndDlg, IDC_RAD_TIMEOUT, TRUE);
+ SetDlgItemInt(hwndDlg, IDC_ED_TIMEOUT, options.default_timeout, FALSE);
+ }
+ if(options.right_icon) CheckDlgButton(hwndDlg, IDC_RAD_RIGHTICON, TRUE);
+ else CheckDlgButton(hwndDlg, IDC_RAD_LEFTICON, TRUE);
+
+ if(ServiceExists(MS_AV_DRAWAVATAR)) {
+ switch(options.av_layout) {
+ case PAV_NONE: CheckDlgButton(hwndDlg, IDC_RAD_NOAV, TRUE); break;
+ case PAV_RIGHT: CheckDlgButton(hwndDlg, IDC_RAD_RIGHTAV, TRUE); break;
+ case PAV_LEFT: CheckDlgButton(hwndDlg, IDC_RAD_LEFTAV, TRUE); break;
+ }
+ } else {
+ CheckDlgButton(hwndDlg, IDC_RAD_NOAV, TRUE);
+ HWND hw = GetDlgItem(hwndDlg, IDC_RAD_RIGHTAV);
+ EnableWindow(hw, FALSE);
+ hw = GetDlgItem(hwndDlg, IDC_RAD_LEFTAV);
+ EnableWindow(hw, FALSE);
+ }
+
+ SetDlgItemInt(hwndDlg, IDC_ED_WIDTH, options.win_width, FALSE);
+ SetDlgItemInt(hwndDlg, IDC_ED_MAXHEIGHT, options.win_max_height, FALSE);
+ SetDlgItemInt(hwndDlg, IDC_ED_AVSIZE, options.av_size, FALSE);
+ SetDlgItemInt(hwndDlg, IDC_ED_INDENT, options.text_indent, FALSE);
+ SetDlgItemInt(hwndDlg, IDC_ED_SBWIDTH, options.sb_width, FALSE);
+ SetDlgItemInt(hwndDlg, IDC_ED_PADDING, options.padding, FALSE);
+
+ switch(options.location) {
+ case PL_BOTTOMRIGHT: CheckDlgButton(hwndDlg, IDC_RAD_BOTTOMRIGHT, TRUE); break;
+ case PL_BOTTOMLEFT: CheckDlgButton(hwndDlg, IDC_RAD_BOTTOMLEFT, TRUE); break;
+ case PL_TOPRIGHT: CheckDlgButton(hwndDlg, IDC_RAD_TOPRIGHT, TRUE); break;
+ case PL_TOPLEFT: CheckDlgButton(hwndDlg, IDC_RAD_TOPLEFT, TRUE); break;
+ }
+
+ SetDlgItemInt(hwndDlg, IDC_ED_TRANS, options.opacity, FALSE);
+ CheckDlgButton(hwndDlg, IDC_CHK_BORDER, options.border);
+ CheckDlgButton(hwndDlg, IDC_CHK_ROUNDCORNERS, options.round);
+ CheckDlgButton(hwndDlg, IDC_CHK_ROUNDCORNERSAV, options.av_round);
+
+ CheckDlgButton(hwndDlg, IDC_CHK_ANIMATE, options.animate);
+ CheckDlgButton(hwndDlg, IDC_CHK_TRANSBG, options.trans_bg);
+
+ return FALSE;
+ case WM_COMMAND:
+ if ( HIWORD( wParam ) == CBN_SELCHANGE) {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ } else if ( HIWORD( wParam ) == EN_CHANGE && ( HWND )lParam == GetFocus()) {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ } else if ( HIWORD( wParam ) == BN_CLICKED ) {
+ if(LOWORD(wParam) == IDC_BTN_PREVIEW) {
+ ShowExamplePopups();
+ } else {
+ switch( LOWORD( wParam )) {
+ case IDC_RAD_NOTIMEOUT:
+ {
+ HWND hw = GetDlgItem(hwndDlg, IDC_ED_TIMEOUT);
+ EnableWindow(hw, IsDlgButtonChecked(hwndDlg, IDC_RAD_TIMEOUT));
+ }
+ break;
+ case IDC_RAD_TIMEOUT:
+ {
+ HWND hw = GetDlgItem(hwndDlg, IDC_ED_TIMEOUT);
+ EnableWindow(hw, IsDlgButtonChecked(hwndDlg, IDC_RAD_TIMEOUT));
+ }
+ break;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ break;
+ case WM_NOTIFY:
+ if(IsWindowVisible(hwndDlg) && ((LPNMHDR) lParam)->hwndFrom == GetDlgItem(hwndDlg, IDC_LST_STATUS)) {
+ switch (((LPNMHDR) lParam)->code) {
+
+ case LVN_ITEMCHANGED:
+ {
+ NMLISTVIEW *nmlv = (NMLISTVIEW *)lParam;
+ if ((nmlv->uNewState ^ nmlv->uOldState) & LVIS_STATEIMAGEMASK) {
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ }
+ }
+ break;
+ }
+ } else
+ if (((LPNMHDR)lParam)->code == (unsigned)PSN_APPLY ) {
+ BOOL trans;
+ int new_val;
+ if(IsDlgButtonChecked(hwndDlg, IDC_RAD_NOTIMEOUT))
+ options.default_timeout = -1;
+ else {
+ new_val = GetDlgItemInt(hwndDlg, IDC_ED_TIMEOUT, &trans, FALSE);
+ if(trans) options.default_timeout = new_val;
+ }
+ if(options.default_timeout == 0) {
+ SetDlgItemInt(hwndDlg, IDC_ED_TIMEOUT, options.default_timeout, FALSE);
+ MessageBox(hwndDlg, TranslateT("You cannot set a default timeout of 0.\nValue has been reset."), TranslateT("Error"), MB_OK | MB_ICONWARNING);
+ options.default_timeout = 7; // prevent instant timeout
+ }
+
+ new_val = GetDlgItemInt(hwndDlg, IDC_ED_WIDTH, &trans, FALSE);
+ if(trans) options.win_width = new_val;
+ new_val = GetDlgItemInt(hwndDlg, IDC_ED_MAXHEIGHT, &trans, FALSE);
+ if(trans) options.win_max_height = new_val;
+ new_val = GetDlgItemInt(hwndDlg, IDC_ED_AVSIZE, &trans, FALSE);
+ if(trans) options.av_size = new_val;
+ new_val = GetDlgItemInt(hwndDlg, IDC_ED_INDENT, &trans, FALSE);
+ if(trans) options.text_indent = new_val;
+ new_val = GetDlgItemInt(hwndDlg, IDC_ED_SBWIDTH, &trans, FALSE);
+ if(trans) options.sb_width = new_val;
+ new_val = GetDlgItemInt(hwndDlg, IDC_ED_PADDING, &trans, FALSE);
+ if(trans) options.padding = new_val;
+
+ options.location = (PopupLocation)SendDlgItemMessage(hwndDlg, IDC_CMB_PLACEMENT, CB_GETCURSEL, 0, 0);
+ options.right_icon = (SendDlgItemMessage(hwndDlg, IDC_CMB_ICON, CB_GETCURSEL, 0, 0) == 1);
+ options.av_layout = (PopupAvLayout)SendDlgItemMessage(hwndDlg, IDC_CMB_AV, CB_GETCURSEL, 0, 0);
+ options.time_layout = (PopupTimeLayout)SendDlgItemMessage(hwndDlg, IDC_CMB_TIME, CB_GETCURSEL, 0, 0);
+
+ new_val = GetDlgItemInt(hwndDlg, IDC_ED_TRANS, &trans, FALSE);
+ if(trans) options.opacity = new_val;
+ options.border = IsDlgButtonChecked(hwndDlg, IDC_CHK_BORDER) && IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHK_BORDER)) ? true : false;
+ options.round = IsDlgButtonChecked(hwndDlg, IDC_CHK_ROUNDCORNERS) && IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHK_ROUNDCORNERS)) ? true : false;
+ options.av_round = IsDlgButtonChecked(hwndDlg, IDC_CHK_ROUNDCORNERSAV) && IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHK_ROUNDCORNERSAV)) ? true : false;
+ options.animate = IsDlgButtonChecked(hwndDlg, IDC_CHK_ANIMATE) ? true : false;
+ options.trans_bg = IsDlgButtonChecked(hwndDlg, IDC_CHK_TRANSBG) ? true : false;
+ options.global_hover = IsDlgButtonChecked(hwndDlg, IDC_CHK_GLOBALHOVER) ? true : false;
+
+ int i = 0;
+ for (; i < 10; i++)
+ options.disable_status[i] = (ListView_GetCheckState(GetDlgItem(hwndDlg, IDC_LST_STATUS), i) == 1);
+ options.disable_full_screen = (ListView_GetCheckState(GetDlgItem(hwndDlg, IDC_LST_STATUS), i) == 1);
+
+ SaveOptions();
+ return TRUE;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+POPUPCLASS *newclasses = 0;
+static INT_PTR CALLBACK DlgProcOptsClasses(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ {
+ if(num_classes) {
+ newclasses = (POPUPCLASS *)mir_alloc(num_classes * sizeof(POPUPCLASS));
+ memcpy(newclasses, classes, num_classes * sizeof(POPUPCLASS));
+
+ POPUPCLASS *pc;
+ int index;
+ for(int i = 0; i < num_classes; i++) {
+ pc = &newclasses[i];
+ if(pc->flags & PCF_UNICODE) {
+ index = SendDlgItemMessageW(hwndDlg, IDC_LST_CLASSES, LB_ADDSTRING, 0, (LPARAM)pc->pwszDescription);
+ } else {
+ index = SendDlgItemMessageA(hwndDlg, IDC_LST_CLASSES, LB_ADDSTRING, 0, (LPARAM)pc->pszDescription);
+ }
+ SendDlgItemMessage(hwndDlg, IDC_LST_CLASSES, LB_SETITEMDATA, index, i);
+ }
+ }
+ }
+ return FALSE;
+ case WM_COMMAND:
+ if ( LOWORD(wParam) == IDC_LST_CLASSES && HIWORD( wParam ) == LBN_SELCHANGE) {
+ int index = SendDlgItemMessage(hwndDlg, IDC_LST_CLASSES, LB_GETCURSEL, 0, 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_PREVIEW), index != -1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_COL_TEXT), index != -1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_COL_BG), index != -1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_TIMEOUT), index != -1);
+ if(index != -1) {
+ int i = SendDlgItemMessage(hwndDlg, IDC_LST_CLASSES, LB_GETITEMDATA, index, 0);
+ SendDlgItemMessage(hwndDlg, IDC_COL_TEXT, CPM_SETCOLOUR, 0, (LPARAM)newclasses[i].colorText);
+ SendDlgItemMessage(hwndDlg, IDC_COL_BG, CPM_SETCOLOUR, 0, (LPARAM)newclasses[i].colorBack);
+ CheckDlgButton(hwndDlg, IDC_CHK_TIMEOUT, newclasses[i].iSeconds != -1);
+ SetDlgItemInt(hwndDlg, IDC_ED_TIMEOUT, newclasses[i].iSeconds, TRUE);
+ }
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ED_TIMEOUT), index != -1 && IsDlgButtonChecked(hwndDlg, IDC_CHK_TIMEOUT));
+ return TRUE;
+ } else if ( HIWORD( wParam ) == EN_CHANGE && ( HWND )lParam == GetFocus()) {
+ int index = SendDlgItemMessage(hwndDlg, IDC_LST_CLASSES, LB_GETCURSEL, 0, 0);
+ if(index != -1) {
+ int i = SendDlgItemMessage(hwndDlg, IDC_LST_CLASSES, LB_GETITEMDATA, index, 0);
+ BOOL tr;
+ int t = GetDlgItemInt(hwndDlg, IDC_ED_TIMEOUT, &tr, FALSE);
+ newclasses[i].iSeconds = t;
+
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ } else {
+ int index = SendDlgItemMessage(hwndDlg, IDC_LST_CLASSES, LB_GETCURSEL, 0, 0);
+ if(index != -1) {
+ int i = SendDlgItemMessage(hwndDlg, IDC_LST_CLASSES, LB_GETITEMDATA, index, 0);
+ switch(LOWORD(wParam)) {
+ case IDC_CHK_TIMEOUT:
+ {
+ BOOL isChecked = IsDlgButtonChecked(hwndDlg, IDC_CHK_TIMEOUT);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ED_TIMEOUT), isChecked);
+ if(isChecked) newclasses[i].iSeconds = 0;
+ else newclasses[i].iSeconds = -1;
+ SetDlgItemInt(hwndDlg, IDC_ED_TIMEOUT, newclasses[i].iSeconds, TRUE);
+ }
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ break;
+ case IDC_COL_TEXT:
+ newclasses[i].colorText = SendDlgItemMessage(hwndDlg, IDC_COL_TEXT, CPM_GETCOLOUR, 0, 0);
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ break;
+ case IDC_COL_BG:
+ newclasses[i].colorBack = SendDlgItemMessage(hwndDlg, IDC_COL_BG, CPM_GETCOLOUR, 0, 0);
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ break;
+ case IDC_BTN_PREVIEW:
+ if(newclasses[i].flags & PCF_UNICODE) {
+ POPUPCLASS pc = newclasses[i];
+ pc.PluginWindowProc = 0;
+ POPUPDATACLASS d = {sizeof(d), pc.pszName};
+ d.pwszTitle = L"Preview";
+ d.pwszText = L"The quick brown fox jumps over the lazy dog.";
+ CallService(MS_POPUP_ADDPOPUPCLASS, (WPARAM)&pc, (LPARAM)&d);
+ } else {
+ POPUPCLASS pc = newclasses[i];
+ pc.PluginWindowProc = 0;
+ POPUPDATACLASS d = {sizeof(d), pc.pszName};
+ d.pszTitle = "Preview";
+ d.pszText = "The quick brown fox jumps over the lazy dog.";
+ CallService(MS_POPUP_ADDPOPUPCLASS, (WPARAM)&pc, (LPARAM)&d);
+ }
+ break;
+ }
+ }
+ }
+ break;
+ case WM_NOTIFY:
+ if (((LPNMHDR)lParam)->code == (unsigned)PSN_APPLY ) {
+ memcpy(classes, newclasses, num_classes * sizeof(POPUPCLASS));
+ char setting[256];
+ for(int i = 0; i < num_classes; i++) {
+ mir_snprintf(setting, 256, "%s/Timeout", classes[i].pszName);
+ DBWriteContactSettingWord(0, MODULE, setting, classes[i].iSeconds);
+ mir_snprintf(setting, 256, "%s/TextCol", classes[i].pszName);
+ DBWriteContactSettingDword(0, MODULE, setting, (DWORD)classes[i].colorText);
+ mir_snprintf(setting, 256, "%s/BgCol", classes[i].pszName);
+ DBWriteContactSettingDword(0, MODULE, setting, (DWORD)classes[i].colorBack);
+ }
+ return TRUE;
+ }
+ break;
+ case WM_DESTROY:
+ mir_free(newclasses);
+ break;
+ }
+ return 0;
+}
+
+int OptInit(WPARAM wParam, LPARAM lParam) {
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.position = -790000000;
+ odp.hInstance = hInst;
+ odp.pszTitle = LPGEN("PopUps");
+
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT1);
+ odp.pszTab = LPGEN("Settings");
+ odp.pfnDlgProc = DlgProcOpts1;
+ Options_AddPage(wParam, &odp);
+
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_CLASSES);
+ odp.pszTab = LPGEN("Classes");
+ odp.pfnDlgProc = DlgProcOptsClasses;
+ Options_AddPage(wParam, &odp);
+
+ return 0;
+}
+
+HANDLE hEventOptInit;
+void InitOptions() {
+ hEventOptInit = HookEvent(ME_OPT_INITIALISE, OptInit);
+
+ // an icon for preview popups
+ hPopupIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
+
+ LoadOptions();
+}
+
+void DeinitOptions() {
+ UnhookEvent(hEventOptInit);
+}
diff --git a/plugins/YAPP/src/options.h b/plugins/YAPP/src/options.h
new file mode 100644
index 0000000000..55b94d17db
--- /dev/null
+++ b/plugins/YAPP/src/options.h
@@ -0,0 +1,36 @@
+#ifndef _OPTIONS_INC
+#define _OPTIONS_INC
+
+typedef enum {PL_BOTTOMRIGHT=0, PL_BOTTOMLEFT=1, PL_TOPRIGHT=2, PL_TOPLEFT=3} PopupLocation;
+typedef enum {PAV_NONE=0, PAV_LEFT=1, PAV_RIGHT=2} PopupAvLayout;
+typedef enum {PT_NONE=0, PT_LEFT=1, PT_RIGHT=2, PT_WITHAV=3} PopupTimeLayout;
+typedef struct {
+ int win_width, win_max_height, av_size; //tweety
+ int default_timeout;
+ PopupLocation location;
+ int opacity;
+ bool border;
+ bool round, av_round;
+ bool animate;
+ bool trans_bg;
+ bool use_mim_monitor;
+ bool right_icon;
+ PopupAvLayout av_layout;
+ bool disable_status[10];
+ int text_indent;
+ bool global_hover;
+ PopupTimeLayout time_layout;
+ bool disable_full_screen;
+ bool drop_shadow;
+ int sb_width;
+ int padding, av_padding;
+} Options;
+
+extern Options options;
+
+void InitOptions();
+void LoadOptions();
+void LoadModuleDependentOptions();
+void DeinitOptions();
+
+#endif
diff --git a/plugins/YAPP/src/popwin.cpp b/plugins/YAPP/src/popwin.cpp
new file mode 100644
index 0000000000..682a3f7b05
--- /dev/null
+++ b/plugins/YAPP/src/popwin.cpp
@@ -0,0 +1,772 @@
+#include "common.h"
+#include "popwin.h"
+#include "message_pump.h"
+#include "options.h"
+
+HMODULE hUserDll;
+BOOL (WINAPI *MySetLayeredWindowAttributes)(HWND,COLORREF,BYTE,DWORD) = 0;
+BOOL (WINAPI *MyAnimateWindow)(HWND hWnd,DWORD dwTime,DWORD dwFlags) = 0;
+HMONITOR (WINAPI *MyMonitorFromRect)(LPCRECT rect, DWORD flags) = 0;
+BOOL (WINAPI *MyGetMonitorInfo)(HMONITOR hMonitor, LPMONITORINFO mi) = 0;
+
+#define ID_CLOSETIMER 0x0101
+#define ID_MOVETIMER 0x0102
+
+DWORD pop_start_x, pop_start_y;
+int global_mouse_in = 0;
+
+void trimW(wchar_t *str) {
+ int len = (int)wcslen(str), pos;
+ // trim whitespace (e.g. from OTR detection)
+ for(pos = len - 1; pos >= 0; pos--) {
+ if(str[pos] == L' ' || str[pos] == L'\t' || str[pos] == L'\r' || str[pos] == L'\n') str[pos] = 0;
+ else break;
+ }
+
+ // remove tabs
+ for(pos = len - 1; pos >= 0; pos--)
+ if(str[pos] == L'\t') str[pos] = L' ';
+}
+
+void SetStartValues(void)
+{
+ RECT wa_rect;
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &wa_rect, 0);
+ if (options.use_mim_monitor && MyMonitorFromRect && MyGetMonitorInfo)
+ {
+ RECT clr;
+ GetWindowRect((HWND)CallService(MS_CLUI_GETHWND, 0, 0), &clr);
+ HMONITOR hMonitor = MyMonitorFromRect(&clr, MONITOR_DEFAULTTONEAREST);
+ if (hMonitor)
+ {
+ MONITORINFO mi;
+ mi.cbSize = sizeof(mi);
+ if (MyGetMonitorInfo(hMonitor, &mi))
+ wa_rect = mi.rcWork;
+ }
+ }
+
+ if(options.location == PL_BOTTOMRIGHT || options.location == PL_TOPRIGHT)
+ pop_start_x = wa_rect.right - options.win_width - 1;
+ else
+ pop_start_x = wa_rect.left + 1;
+
+ if(options.location == PL_BOTTOMRIGHT || options.location == PL_BOTTOMLEFT)
+ pop_start_y = wa_rect.bottom - 1;
+ else
+ pop_start_y = wa_rect.top + 1;
+}
+
+struct HWNDStackNode {
+ HWND hwnd;
+ struct HWNDStackNode *next;
+};
+
+HWNDStackNode *hwnd_stack_top = 0;
+int stack_size = 0;
+
+void RepositionWindows() {
+ HWNDStackNode *current;
+ int x = pop_start_x, y = pop_start_y;
+ int height;//, total_height = 0;
+
+ /*
+ current = hwnd_stack_top;
+ while(current) {
+ SendMessage(current->hwnd, PUM_GETHEIGHT, (WPARAM)&height, 0);
+ total_height += height;
+ current = current->next;
+ }
+ */
+
+ current = hwnd_stack_top;
+ while(current) {
+ SendMessage(current->hwnd, PUM_GETHEIGHT, (WPARAM)&height, 0);
+ if(options.location == PL_BOTTOMRIGHT || options.location == PL_BOTTOMLEFT) y -= height + 1;
+ SendMessage(current->hwnd, PUM_MOVE, (WPARAM)x, (LPARAM)y);
+ if(options.location == PL_TOPRIGHT || options.location == PL_TOPLEFT) y += height + 1;
+
+ current = current->next;
+ }
+}
+
+void AddWindowToStack(HWND hwnd) {
+ SetStartValues();
+
+ HWNDStackNode *new_node = (HWNDStackNode *)mir_alloc(sizeof(HWNDStackNode));
+ new_node->hwnd = hwnd;
+ new_node->next = hwnd_stack_top;
+ hwnd_stack_top = new_node;
+
+ int height;
+ SendMessage(hwnd, PUM_GETHEIGHT, (WPARAM)&height, 0);
+
+ int x = pop_start_x, y = pop_start_y;
+ if(options.location == PL_BOTTOMRIGHT || options.location == PL_TOPRIGHT)
+ x += options.win_width;
+ else
+ x -= options.win_width;
+
+ if(options.location == PL_BOTTOMRIGHT || options.location == PL_BOTTOMLEFT) y -= height;
+ SetWindowPos(hwnd, 0, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+ if(options.location == PL_TOPRIGHT || options.location == PL_TOPLEFT) y += height;
+
+ stack_size++;
+
+ RepositionWindows();
+}
+
+void RemoveWindowFromStack(HWND hwnd) {
+ HWNDStackNode *current = hwnd_stack_top, *prev = 0;
+ while(current) {
+ if(current->hwnd == hwnd) {
+ if(prev) {
+ prev->next = current->next;
+ } else {
+ hwnd_stack_top = current->next;
+ }
+ mir_free(current);
+ stack_size--;
+ break;
+ }
+
+ prev = current;
+ current = current->next;
+ }
+
+ if(hwnd_stack_top) RepositionWindows();
+}
+
+void ClearStack() {
+ while(hwnd_stack_top) {
+ DestroyWindow(hwnd_stack_top->hwnd);
+ }
+}
+
+void BroadcastMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+ HWNDStackNode *current = hwnd_stack_top;
+ while(current) {
+ SendMessage(current->hwnd, msg, wParam, lParam);
+ current = current->next;
+ }
+}
+
+struct PopupWindowData {
+ PopupData *pd;
+ int new_x, new_y;
+ bool is_round, av_is_round, mouse_in, close_on_leave;
+ bool custom_col;
+ HBRUSH bkBrush, barBrush, underlineBrush;
+ HPEN bPen;
+ TCHAR tbuff[128];
+ int tb_height, av_height, text_height, time_height, time_width;
+ int real_av_width, real_av_height;
+ bool have_av;
+ HANDLE hNotify;
+};
+
+LRESULT CALLBACK PopupWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+ PopupWindowData *pwd = (PopupWindowData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ PopupData *pd = 0;
+ if(pwd) pd = pwd->pd;
+
+ switch(uMsg) {
+ case WM_CREATE:
+ {
+ CREATESTRUCT *cs = (CREATESTRUCT *)lParam;
+ pwd = (PopupWindowData *)mir_alloc(sizeof(PopupWindowData));
+ pd = (PopupData *)cs->lpCreateParams;
+ pwd->pd = pd;
+ pwd->hNotify = 0;
+
+ trimW(pwd->pd->pwzTitle);
+ trimW(pwd->pd->pwzText);
+
+ pwd->is_round = options.round;
+ pwd->av_is_round = options.av_round;
+ pwd->mouse_in = pwd->close_on_leave = false;
+ pwd->custom_col = (pd->colorBack != pd->colorText);
+
+ pwd->tb_height = pwd->av_height = pwd->text_height = pwd->time_height = pwd->time_width = 0;
+ pwd->have_av = false;
+
+ if(pwd->custom_col) {
+ pwd->bkBrush = CreateSolidBrush(pd->colorBack);
+
+ //pwd->barBrush = CreateSolidBrush(pd->colorBack / 2); // make sidebar a dark version of the bg
+ //DWORD darkBg = (((pd->colorBack & 0xff0000) >> 1) & 0xff0000) + (((pd->colorBack & 0xff00) >> 1) & 0xff00) + (((pd->colorBack & 0xff) >> 1) & 0xff);
+ //DWORD darkBg = (pdColorBack >> 1) & 0x7f7f7f; // equivalent to above :)
+
+ DWORD darkBg = pd->colorBack - ((pd->colorBack >> 2) & 0x3f3f3f); // 3/4 of current individual RGB components
+ pwd->barBrush = CreateSolidBrush(darkBg); // make sidebar a dark version of the bg
+ pwd->underlineBrush = CreateSolidBrush(pd->colorBack); // make sidebar a dark version of the bg
+ } else {
+ pwd->bkBrush = CreateSolidBrush(colBg);
+ pwd->barBrush = CreateSolidBrush(colSidebar);
+ pwd->underlineBrush = CreateSolidBrush(colTitleUnderline);
+ }
+
+ if(options.border) pwd->bPen = (HPEN)CreatePen(PS_SOLID, 1, colBorder);
+ else pwd->bPen = CreatePen(PS_SOLID, 1, pwd->custom_col ? pd->colorBack : colBg);
+
+ SYSTEMTIME st;
+ GetLocalTime(&st);
+ GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, 0, pwd->tbuff, 128);
+
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pwd);
+
+ if(pd->timeout == -1 || (pd->timeout == 0 && options.default_timeout == -1)) {
+ // make a really long timeout - say 7 days? ;)
+ SetTimer(hwnd, ID_CLOSETIMER, 7 * 24 * 60 * 60 * 1000, 0);
+ } else {
+ if(pd->timeout == 0) {
+ SetTimer(hwnd, ID_CLOSETIMER, options.default_timeout * 1000, 0);
+ } else {
+ SetTimer(hwnd, ID_CLOSETIMER, pd->timeout * 1000, 0);
+ }
+ }
+
+ AddWindowToStack(hwnd); // this updates our size
+ }
+
+ // transparency
+#ifdef WS_EX_LAYERED
+ SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
+#endif
+
+#ifdef CS_DROPSHADOW
+ if (options.drop_shadow) {
+ SetClassLong(hwnd, GCL_STYLE, CS_DROPSHADOW);
+ }
+#endif
+
+#ifdef LWA_ALPHA
+ if(MySetLayeredWindowAttributes) {
+ MySetLayeredWindowAttributes(hwnd, RGB(0,0,0), (int)(options.opacity / 100.0 * 255), LWA_ALPHA);
+ if(options.trans_bg) {
+ COLORREF bg;
+ if(pd->colorBack == pd->colorText)
+ bg = colBg;
+ else
+ bg = pd->colorBack;
+ MySetLayeredWindowAttributes(hwnd, bg, 0, LWA_COLORKEY);
+ }
+ }
+#endif
+ PostMessage(hwnd, PM_INIT, (WPARAM)hwnd, 0);
+ return 0;
+ case WM_MOUSEMOVE:
+ if(pwd && !pwd->mouse_in) {
+ pwd->mouse_in = true;
+ global_mouse_in++;
+ TRACKMOUSEEVENT tme = { sizeof(tme) };
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = hwnd;
+ TrackMouseEvent(&tme);
+ }
+ break;
+ case WM_MOUSELEAVE:
+ if(pwd && pwd->mouse_in) {
+ pwd->mouse_in = false;
+ global_mouse_in--;
+ }
+ return 0;
+ case WM_LBUTTONUP:
+ // fake STN_CLICKED notification
+ SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, STN_CLICKED), 0);
+ break;
+ case WM_TIMER:
+ if(wParam == ID_CLOSETIMER) {
+ KillTimer(hwnd, ID_CLOSETIMER);
+ if(pwd->mouse_in || (options.global_hover && global_mouse_in))
+ SetTimer(hwnd, ID_CLOSETIMER, 800, 0); // reset timer if mouse in window - allow another 800 ms
+ else {
+ PostMessage(hwnd, PM_DESTROY, 0, 0);
+ }
+ return TRUE;
+ } else if(wParam == ID_MOVETIMER) {
+ RECT r;
+ GetWindowRect(hwnd, &r);
+
+ if(r.left == pwd->new_x && r.top == pwd->new_y) {
+ KillTimer(hwnd, ID_MOVETIMER);
+ return TRUE;
+ }
+ int adj_x = (pwd->new_x - r.left) / 4, adj_y = (pwd->new_y - r.top) / 4;
+ if(adj_x == 0) adj_x = (pwd->new_x - r.left);
+ if(adj_y == 0) adj_y = (pwd->new_y - r.top);
+
+ int x = r.left + adj_x, y = r.top + adj_y;
+ //SetWindowPos(hwnd, 0, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOCOPYBITS);
+ SetWindowPos(hwnd, 0, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
+
+
+ /*
+ // clip to monitor bounds (paints badly!)
+ //HDC hdc = GetDC(hwnd);
+ HMONITOR hMonitor = MonitorFromRect(&r, MONITOR_DEFAULTTONEAREST);
+ MONITORINFO mi;
+ mi.cbSize = sizeof(mi);
+ GetMonitorInfo(hMonitor, &mi);
+
+ POINT p[2];
+ p[0].x = mi.rcWork.left; p[0].y = mi.rcWork.top; p[1].x = mi.rcWork.right; p[1].y = mi.rcWork.bottom;
+ //LPtoDP(hdc, p, 2);
+ ScreenToClient(hwnd, &p[0]); ScreenToClient(hwnd, &p[1]);
+
+ HRGN hMonRgn = CreateRectRgn(p[0].x, p[0].y, p[1].x, p[1].y);
+ //ReleaseDC(hwnd, hdc);
+
+ RECT cr; GetClientRect(hwnd, &cr);
+ HRGN hWndRgn = CreateRectRgn(cr.left, cr.top, cr.right + 3, cr.bottom + 3);
+ CombineRgn(hMonRgn, hMonRgn, hWndRgn, RGN_AND);
+
+ // round corners
+ if(options.round) {
+ HRGN hRgn1;
+ int v,h, w=10;
+ h=(r.right-r.left)>(w*2)?w:(r.right-r.left);
+ v=(r.bottom-r.top)>(w*2)?w:(r.bottom-r.top);
+ h=(h<v)?h:v;
+ hRgn1=CreateRoundRectRgn(0,0,(r.right-r.left+1),(r.bottom-r.top+1),h,h);
+ CombineRgn(hMonRgn, hMonRgn, hRgn1, RGN_AND);
+ DeleteObject(hRgn1);
+ }
+
+ SetWindowRgn(hwnd, hMonRgn, TRUE);
+
+ DeleteObject(hWndRgn);
+
+ InvalidateRect(hwnd, 0, TRUE);
+ */
+
+ if (!IsWindowVisible(hwnd)) {
+ ShowWindow(hwnd, SW_SHOWNOACTIVATE);
+ UpdateWindow(hwnd);
+ }
+ return TRUE;
+ }
+ break;
+ case WM_ERASEBKGND:
+ {
+ HDC hdc = (HDC) wParam;
+ RECT r, r_bar;
+ GetClientRect(hwnd, &r);
+
+ // bg
+ FillRect(hdc, &r, pwd->bkBrush);
+ // sidebar
+ r_bar = r;
+ r_bar.right = r.left + options.sb_width;
+ FillRect(hdc, &r_bar, pwd->barBrush);
+ // border
+ if(options.border) {
+
+ HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH));
+ HPEN hOldPen = (HPEN)SelectObject(hdc, pwd->bPen);
+
+ int h = 0;
+ if(options.round) {
+ int v;
+ int w=14;
+ h=(r.right-r.left)>(w*2)?w:(r.right-r.left);
+ v=(r.bottom-r.top)>(w*2)?w:(r.bottom-r.top);
+ h=(h<v)?h:v;
+ //} else {
+ // Rectangle(hdc, r.left, r.top, (r.right - r.left), (r.bottom - r.top));
+ }
+ RoundRect(hdc, 0, 0, (r.right - r.left), (r.bottom - r.top), h, h);
+
+ SelectObject(hdc, hOldBrush);
+ SelectObject(hdc, hOldPen);
+ }
+
+ }
+ return TRUE;
+ case WM_PAINT:
+ {
+ RECT r;
+ //if(GetUpdateRect(hwnd, &r, TRUE)) {
+ PAINTSTRUCT ps;
+ BeginPaint(hwnd, &ps);
+ HDC hdc = ps.hdc;
+ GetClientRect(hwnd, &r);
+
+ // text background
+ //if(pwd->custom_col) SetBkColor(ps.hdc, pd->colorBack);
+ //else SetBkColor(ps.hdc, colBg);
+ SetBkMode(hdc, TRANSPARENT);
+
+ // avatar & time if with avatar
+ if(options.av_layout != PAV_NONE && (pwd->have_av || options.time_layout == PT_WITHAV)) {
+ RECT avr;
+ avr.top = options.av_padding;
+
+ if(options.av_layout == PAV_LEFT) {
+ avr.left = r.left + options.av_padding;
+ if(pwd->have_av && options.time_layout == PT_WITHAV) avr.right = avr.left + max(pwd->real_av_width, pwd->time_width);
+ else if(pwd->have_av) avr.right = avr.left + pwd->real_av_width;
+ else avr.right = avr.left + pwd->time_width;
+ r.left = avr.right;
+ } else if(options.av_layout == PAV_RIGHT) {
+ avr.right = r.right - options.av_padding;
+ if(pwd->have_av && options.time_layout == PT_WITHAV) avr.left = avr.right - max(pwd->real_av_width, pwd->time_width);
+ else if(pwd->have_av) avr.left = avr.right - pwd->real_av_width;
+ else avr.left = avr.right - pwd->time_width;
+ r.right = avr.left;
+ }
+
+ if(options.time_layout == PT_WITHAV) {
+ avr.top = options.padding;
+ avr.bottom = avr.top + pwd->time_height;
+ if(pwd->custom_col) SetTextColor(ps.hdc, pd->colorText);
+ else SetTextColor(ps.hdc, colTime);
+ if(hFontTime) SelectObject(hdc, (HGDIOBJ)hFontTime);
+ DrawText(ps.hdc, pwd->tbuff, (int)_tcslen(pwd->tbuff), &avr, DT_VCENTER | DT_CENTER | DT_LEFT | DT_SINGLELINE | DT_NOPREFIX);
+ avr.top = avr.bottom + options.av_padding;
+ }
+
+ if(pwd->have_av) {
+ // correct for wider time
+ if(options.time_layout == PT_WITHAV && pwd->time_width > options.av_size) {
+ avr.left = avr.left + (pwd->time_width - pwd->real_av_width) / 2;
+ avr.right = avr.left + pwd->real_av_width;
+ }
+ avr.bottom = avr.top + pwd->real_av_height;
+
+ AVATARDRAWREQUEST adr = {0};
+ adr.cbSize = sizeof(adr);
+ adr.hContact = pd->hContact;
+ adr.hTargetDC = ps.hdc;
+ adr.rcDraw = avr;
+ adr.dwFlags = (pwd->av_is_round ? AVDRQ_ROUNDEDCORNER : 0);
+ adr.radius = 5; //(pwd->av_is_round ? 5 : 0);
+
+ CallService(MS_AV_DRAWAVATAR, 0, (LPARAM)&adr);
+ }
+ }
+
+ // title icon
+ int iconx, textxmin = r.left + options.padding, textxmax = r.right - options.padding;
+ if(pd->hIcon) {
+ if(options.right_icon) {
+ iconx = r.right - (16 + options.padding);
+ textxmax -= 16 + options.padding;
+ } else {
+ iconx = r.left + options.padding;
+ textxmin += 16 + options.padding;
+ }
+ DrawIconEx(ps.hdc, iconx, options.padding + (pwd->tb_height - 16) / 2, pd->hIcon, 16, 16, 0, NULL, DI_NORMAL);
+ }
+
+ // title time
+ if(options.time_layout == PT_LEFT || options.time_layout == PT_RIGHT) {
+ RECT ttr;
+ ttr.top = r.top + options.padding; ttr.bottom = ttr.top + pwd->tb_height;
+ if(pwd->custom_col) SetTextColor(ps.hdc, pd->colorText);
+ else SetTextColor(ps.hdc, colTime);
+ if(hFontTime) SelectObject(hdc, (HGDIOBJ)hFontTime);
+ switch(options.time_layout) {
+ case PT_LEFT:
+ ttr.left = textxmin; ttr.right = ttr.left + pwd->time_width;
+ textxmin += pwd->time_width + options.padding;
+ DrawText(ps.hdc, pwd->tbuff, (int)_tcslen(pwd->tbuff), &ttr, DT_VCENTER | DT_LEFT | DT_SINGLELINE | DT_NOPREFIX);
+ break;
+ case PT_RIGHT:
+ ttr.right = textxmax; ttr.left = ttr.right - pwd->time_width;
+ textxmax -= pwd->time_width + options.padding;
+ DrawText(ps.hdc, pwd->tbuff, (int)_tcslen(pwd->tbuff), &ttr, DT_VCENTER | DT_LEFT | DT_SINGLELINE | DT_NOPREFIX);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if(textxmin < options.sb_width) textxmin = options.sb_width + options.padding / 2;
+
+ // title text
+ if(hFontFirstLine) SelectObject(ps.hdc, (HGDIOBJ)hFontFirstLine);
+ RECT tr;
+ tr.left = r.left + options.padding + options.text_indent; tr.right = textxmax; tr.top = r.top + options.padding; tr.bottom = tr.top + pwd->tb_height;
+
+ if(pwd->custom_col) SetTextColor(ps.hdc, pd->colorText);
+ else SetTextColor(ps.hdc, colFirstLine);
+ TCHAR *title = mir_u2t(pd->pwzTitle);
+ DrawText(ps.hdc, title, (int)_tcslen(title), &tr, DT_VCENTER | DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE | DT_NOPREFIX);
+ mir_free(title);
+
+ // title underline
+ RECT tur;
+ tur.left = r.left + options.sb_width + options.padding;
+ tur.right = r.right - options.padding;
+ tur.top = tr.bottom + options.padding/2;
+ tur.bottom = tur.top + 1;
+ FillRect(ps.hdc, &tur, pwd->underlineBrush);
+
+ // second line(s)
+ if(pd->pwzText[0]) {
+ if(hFontSecondLine) SelectObject(ps.hdc, (HGDIOBJ)hFontSecondLine);
+ if (!pwd->custom_col)
+ SetTextColor(ps.hdc, colSecondLine);
+
+ // expand text if no avatar and the time isn't too large
+ if(options.av_layout != PAV_NONE && options.time_layout == PT_WITHAV && pwd->time_height <= pwd->tb_height && !pwd->have_av)
+ GetClientRect(hwnd, &r);
+
+ TCHAR *text = mir_u2t(pd->pwzText);
+ tr.left = r.left + options.padding + options.text_indent; tr.right = r.right - options.padding; tr.top = tr.bottom + options.padding; tr.bottom = r.bottom - options.padding;
+ DrawText(ps.hdc, text, (int)_tcslen(text), &tr, DT_NOPREFIX | DT_WORDBREAK | DT_EXTERNALLEADING | DT_TOP | DT_LEFT | DT_WORD_ELLIPSIS);
+ mir_free(text);
+ }
+
+ EndPaint(hwnd, &ps);
+ //}
+ }
+ return 0;
+
+ case WM_DESTROY:
+ if(pwd->mouse_in) global_mouse_in--;
+
+ ShowWindow(hwnd, SW_HIDE);
+
+ DeleteObject(pwd->bkBrush);
+ DeleteObject(pwd->bPen);
+ DeleteObject(pwd->barBrush);
+ DeleteObject(pwd->underlineBrush);
+ KillTimer(hwnd, ID_MOVETIMER);
+ KillTimer(hwnd, ID_CLOSETIMER);
+
+ RemoveWindowFromStack(hwnd);
+
+ SendMessage(hwnd, PM_DIENOTIFY, 0, 0);
+
+ if (pd) {
+ mir_free(pd->pwzTitle);
+ mir_free(pd->pwzText);
+ mir_free(pd);
+ }
+ mir_free(pwd); pwd = 0; pd = 0;
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
+ break;
+
+ case PUM_UPDATERGN:
+ // round corners
+ if(pwd->is_round) {
+ HRGN hRgn1;
+ RECT r;
+
+ int v,h;
+ int w=11;
+ GetWindowRect(hwnd,&r);
+ h=(r.right-r.left)>(w*2)?w:(r.right-r.left);
+ v=(r.bottom-r.top)>(w*2)?w:(r.bottom-r.top);
+ h=(h<v)?h:v;
+ hRgn1=CreateRoundRectRgn(0,0,(r.right-r.left) + 1,(r.bottom-r.top) + 1,h,h);
+ SetWindowRgn(hwnd,hRgn1,FALSE);
+ }
+ return TRUE;
+
+ case PUM_MOVE:
+ if(options.animate) {
+ KillTimer(hwnd, ID_MOVETIMER);
+ pwd->new_x = (int)wParam;
+ pwd->new_y = (int)lParam;
+ SetTimer(hwnd, ID_MOVETIMER, 10, 0);
+ } else {
+ SetWindowPos(hwnd, 0, (int)wParam, (int)lParam, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
+ if (!IsWindowVisible(hwnd)) {
+ ShowWindow(hwnd, SW_SHOWNOACTIVATE);
+ UpdateWindow(hwnd);
+ }
+ }
+ return TRUE;
+
+ case PUM_SETTEXT:
+ replaceStrT(pd->ptzText, (TCHAR*)lParam);
+ InvalidateRect(hwnd, 0, TRUE);
+ RepositionWindows();
+ return TRUE;
+
+ case PUM_GETCONTACT:
+ {
+ HANDLE *phContact = (HANDLE *)wParam;
+ *phContact = pd->hContact;
+ if(lParam) SetEvent((HANDLE)lParam);
+ }
+ return TRUE;
+ case PUM_GETHEIGHT:
+ {
+ int *pHeight = (int *)wParam;
+ HDC hdc = GetDC(hwnd);
+ SIZE size;
+
+ // time_height + width
+ if(options.time_layout != PT_NONE) {
+ SIZE size_t;
+ if(hFontTime) SelectObject(hdc, (HGDIOBJ)hFontTime);
+ GetTextExtentPoint32(hdc, pwd->tbuff, (int)_tcslen(pwd->tbuff), &size_t);
+ pwd->time_height = size_t.cy;
+ pwd->time_width = size_t.cx;
+ }
+
+ // titlebar height
+ if(hFontFirstLine) SelectObject(hdc, (HGDIOBJ)hFontFirstLine);
+ TCHAR *title = mir_u2t(pd->pwzTitle);
+ GetTextExtentPoint32(hdc, title, (int)_tcslen(title), &size);
+ mir_free(title);
+ pwd->tb_height = size.cy;
+ if(options.time_layout == PT_LEFT || options.time_layout == PT_RIGHT) {
+ if(pwd->tb_height < pwd->time_height) pwd->tb_height = pwd->time_height;
+ }
+ if(pwd->tb_height < 16) pwd->tb_height = 16;
+
+ // avatar height
+ if(options.av_layout != PAV_NONE && ServiceExists(MS_AV_DRAWAVATAR)) {
+ AVATARCACHEENTRY *ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)pd->hContact, 0);
+ if(ace && (ace->dwFlags & AVS_BITMAP_VALID) && !(ace->dwFlags & AVS_HIDEONCLIST)) {
+ if(ace->bmHeight >= ace->bmWidth) {
+ pwd->real_av_height = options.av_size;
+ pwd->real_av_width = options.av_size * ace->bmWidth / ace->bmHeight;
+ } else {
+ pwd->real_av_height = options.av_size * ace->bmHeight / ace->bmWidth;
+ pwd->real_av_width = options.av_size;
+ }
+ pwd->have_av = true;
+ pwd->av_height = pwd->real_av_height;
+ }
+ }
+
+ // text height
+ if (pd->pwzText[0]) {
+ RECT r;
+ r.left = r.top = 0;
+ r.right = options.win_width - 2 * options.padding - options.text_indent;
+ if(pwd->have_av && options.time_layout == PT_WITHAV)
+ r.right -= (max(options.av_size, pwd->time_width) + options.padding);
+ else if(pwd->have_av)
+ r.right -= (options.av_size + options.padding);
+ else if(options.av_layout != PAV_NONE && options.time_layout == PT_WITHAV && pwd->time_height >= pwd->tb_height)
+ r.right -= pwd->time_width + options.padding;
+
+ if(hFontSecondLine) SelectObject(hdc, (HGDIOBJ)hFontSecondLine);
+ TCHAR *text = mir_u2t(pd->pwzText);
+ DrawText(hdc, text, (int)_tcslen(text), &r, DT_CALCRECT | DT_NOPREFIX | DT_WORDBREAK | DT_EXTERNALLEADING | DT_TOP | DT_LEFT | DT_WORD_ELLIPSIS);
+ pwd->text_height = r.bottom;
+ mir_free(text);
+ }
+
+ ReleaseDC(hwnd, hdc);
+
+ if(options.time_layout == PT_WITHAV && options.av_layout != PAV_NONE)
+ *pHeight = max(pwd->tb_height + pwd->text_height + 3 * options.padding, pwd->av_height + pwd->time_height + options.padding + 2 * options.av_padding);
+ else
+ *pHeight = max(pwd->tb_height + pwd->text_height + 3 * options.padding, pwd->av_height + 2 * options.av_padding);
+
+ if (*pHeight > options.win_max_height) *pHeight = options.win_max_height;
+
+ RECT r;
+ GetWindowRect(hwnd, &r);
+ if(r.right - r.left != options.win_width || r.bottom - r.top != *pHeight) {
+ SetWindowPos(hwnd, 0, 0, 0, options.win_width, *pHeight, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
+ SendMessage(hwnd, PUM_UPDATERGN, 0, 0);
+ InvalidateRect(hwnd, 0, TRUE);
+ }
+ }
+ return TRUE;
+ case PUM_GETOPAQUE:
+ {
+ void **pData = (void **)wParam;
+ if(pd) *pData = pd->opaque;
+ if(lParam) SetEvent((HANDLE)lParam);
+ }
+ return TRUE;
+ case PUM_CHANGE:
+ {
+ KillTimer(hwnd, ID_CLOSETIMER);
+ if (pd) {
+ mir_free(pd->pwzTitle);
+ mir_free(pd->pwzText);
+ mir_free(pd);
+ }
+ pwd->pd = pd = (PopupData *)lParam;
+
+ if(pd->timeout != -1) {
+ if(pd->timeout == 0) {
+ SetTimer(hwnd, ID_CLOSETIMER, 7 * 1000, 0);
+ } else {
+ SetTimer(hwnd, ID_CLOSETIMER, pd->timeout * 1000, 0);
+ }
+ } else {
+ // make a really long timeout - say 7 days? ;)
+ SetTimer(hwnd, ID_CLOSETIMER, 7 * 24 * 60 * 60 * 1000, 0);
+ }
+
+ InvalidateRect(hwnd, 0, TRUE);
+ RepositionWindows();
+ }
+ return TRUE;
+
+ case PUM_SETNOTIFYH:
+ pwd->hNotify = (HANDLE)wParam;
+ return TRUE;
+
+ case PUM_UPDATENOTIFY:
+ if(pwd->hNotify == (HANDLE)wParam) {
+ pd->colorBack = MNotifyGetDWord(pwd->hNotify, NFOPT_BACKCOLOR, colBg);
+ pd->colorText = MNotifyGetDWord(pwd->hNotify, NFOPT_TEXTCOLOR, colSecondLine);
+ pd->timeout = MNotifyGetDWord(pwd->hNotify, NFOPT_TIMEOUT, options.default_timeout);
+ pd->hContact = (HANDLE)MNotifyGetDWord(pwd->hNotify, NFOPT_CONTACT, 0);
+ pd->hIcon = (HICON)MNotifyGetDWord(pwd->hNotify, NFOPT_ICON, 0);
+
+ const wchar_t *swzName = MNotifyGetWString(pwd->hNotify, NFOPT_TITLEW, 0);
+ mir_free(pd->pwzTitle);
+ pd->pwzTitle = mir_wstrdup(swzName);
+
+ const wchar_t *swzText = MNotifyGetWString(pwd->hNotify, NFOPT_TEXTW, 0);
+ mir_free(pd->pwzText);
+ pd->pwzText = mir_wstrdup(swzText);
+
+ InvalidateRect(hwnd, 0, TRUE);
+ RepositionWindows();
+ }
+
+ return TRUE;
+ case PUM_KILLNOTIFY:
+ if(pwd->hNotify != (HANDLE)wParam)
+ return TRUE;
+ // drop through
+
+ case PM_DESTROY:
+ PostMPMessage(MUM_DELETEPOPUP, 0, (LPARAM)hwnd);
+ return TRUE;
+ }
+
+
+ if(pd && pd->windowProc)
+ return CallWindowProc(pd->windowProc, hwnd, uMsg, wParam, lParam);
+ else {
+ // provide a way to close popups, if no PluginWindowProc is provided
+ if(uMsg == WM_CONTEXTMENU) {
+ SendMessage(hwnd, PM_DESTROY, 0, 0);
+ return TRUE;
+ } else
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
+ }
+}
+
+void InitWindowStack() {
+ hUserDll = GetModuleHandle(_T("user32.dll"));
+ if (hUserDll) {
+ MySetLayeredWindowAttributes = (BOOL (WINAPI *)(HWND,COLORREF,BYTE,DWORD))GetProcAddress(hUserDll, "SetLayeredWindowAttributes");
+ MyAnimateWindow=(BOOL (WINAPI*)(HWND,DWORD,DWORD))GetProcAddress(hUserDll,"AnimateWindow");
+ MyMonitorFromRect=(HMONITOR (WINAPI*)(LPCRECT,DWORD))GetProcAddress(hUserDll, "MonitorFromRect");
+
+ MyGetMonitorInfo=(BOOL (WINAPI*)(HMONITOR,LPMONITORINFO))GetProcAddress(hUserDll, "GetMonitorInfoW");
+
+ }
+}
+
+void DeinitWindowStack() {
+ ClearStack();
+}
+
diff --git a/plugins/YAPP/src/popwin.h b/plugins/YAPP/src/popwin.h
new file mode 100644
index 0000000000..4d826ceade
--- /dev/null
+++ b/plugins/YAPP/src/popwin.h
@@ -0,0 +1,28 @@
+#ifndef _POPWIN_INC
+#define _POPWIN_INC
+
+#define POP_WIN_CLASS _T(MODULE) _T("YAPPWindowClass")
+
+#define PUM_SETTEXT (WM_USER + 0x020)
+#define PUM_GETCONTACT (WM_USER + 0x021)
+#define PUM_GETOPAQUE (WM_USER + 0x022)
+#define PUM_CHANGE (WM_USER + 0x023)
+#define PUM_MOVE (WM_USER + 0x024)
+#define PUM_GETHEIGHT (WM_USER + 0x025)
+#define PUM_UPDATERGN (WM_USER + 0x026)
+
+#define PUM_SETNOTIFYH (WM_USER + 0x030)
+#define PUM_KILLNOTIFY (WM_USER + 0x031)
+#define PUM_UPDATENOTIFY (WM_USER + 0x032)
+
+void InitWindowStack();
+void DeinitWindowStack();
+
+void BroadcastMessage(UINT msg, WPARAM wParam, LPARAM lParam);
+
+void RepositionWindows();
+
+LRESULT CALLBACK PopupWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+
+#endif
diff --git a/plugins/YAPP/src/resource.h b/plugins/YAPP/src/resource.h
new file mode 100644
index 0000000000..d7db4cda2e
--- /dev/null
+++ b/plugins/YAPP/src/resource.h
@@ -0,0 +1,79 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by popups2.rc
+//
+#define IDD_OPT1 101
+#define IDD_DIALOG1 102
+#define IDD_OPT_NOTIFY 103
+#define IDD_LST_HISTORY 104
+#define IDI_ICON1 105
+#define IDI_POPUP_HISTORY 105
+#define IDI_ICON2 106
+#define IDD_CLASSES 107
+#define IDC_RAD_NOTIMEOUT 1001
+#define IDC_RAD_TIMEOUT 1002
+#define IDC_ED_TIMEOUT 1003
+#define IDC_SPIN_TIMEOUT 1004
+#define IDC_ED_WIDTH 1005
+#define IDC_ED_MAXHEIGHT 1006
+#define IDC_SPIN_WIDTH 1007
+#define IDC_SPIN3 1008
+#define IDC_SPIN_MAXHEIGHT 1009
+#define IDC_RAD_BOTTOMRIGHT 1010
+#define IDC_ED_INDENT 1011
+#define IDC_RAD_BOTTOMLEFT 1012
+#define IDC_ED_SBWIDTH 1012
+#define IDC_SPIN_INDENT 1013
+#define IDC_RAD_TOPRIGHT 1014
+#define IDC_SPIN_SBWIDTH 1014
+#define IDC_RAD_TOPLEFT 1015
+#define IDC_ED_PADDING 1015
+#define IDC_ED_TRANS 1016
+#define IDC_SPIN_TRANS 1017
+#define IDC_CHK_BORDER 1018
+#define IDC_CHK_ROUNDCORNERS 1019
+#define IDC_BTN_PREVIEW 1020
+#define IDC_CHK_ANIMATE 1021
+#define IDC_CHK_TRANSBG 1022
+#define IDC_RAD_RIGHTICON 1023
+#define IDC_SPIN_INDENT2 1023
+#define IDC_SPIN_PADDING 1023
+#define IDC_CHK_GLOBALHOVER 1024
+#define IDC_RAD_LEFTICON 1025
+#define IDC_CHK_ROUNDCORNERSAV 1025
+#define IDC_RAD_NOAV 1026
+#define IDC_RAD_RIGHTAV 1027
+#define IDC_RAD_NOAV3 1028
+#define IDC_RAD_LEFTAV 1029
+#define IDC_ED_MAXHEIGHT2 1030
+#define IDC_ED_AVSIZE 1031
+#define IDC_SPIN_AVSIZE 1032
+#define IDC_LST_STATUS 1033
+#define IDC_CMB_PLACEMENT 1034
+#define IDC_CMB_ICON 1035
+#define IDC_CMB_AV 1036
+#define IDC_CMB_AV2 1037
+#define IDC_CMB_TIME 1038
+#define IDC_CUSTOM1 1039
+#define IDC_COL_TEXT 1039
+#define IDC_BORDERCOLOUR 1040
+#define IDC_COL_BG 1040
+#define IDC_CLOSE 1041
+#define IDC_LIST3 1042
+#define IDC_LST_HISTORY 1043
+#define IDC_HISTORY_FILTER 1044
+#define IDC_HISTORY_FILTER_CASESENSITIVE 1046
+#define IDC_LST_CLASSES 1047
+#define IDC_CHK_TIMEOUT 1048
+#define IDC_BUTTON1 1050
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 108
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1051
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/plugins/YAPP/src/services.cpp b/plugins/YAPP/src/services.cpp
new file mode 100644
index 0000000000..4dd00fcd38
--- /dev/null
+++ b/plugins/YAPP/src/services.cpp
@@ -0,0 +1,524 @@
+#include "common.h"
+#include "services.h"
+#include "popwin.h"
+#include "message_pump.h"
+#include "resource.h"
+#include "yapp_history.h"
+
+#define NUM_SERVICES 20
+HANDLE hService[NUM_SERVICES];
+HANDLE hMenuShowHistory, hMenuToggleOnOff;
+
+void StripBBCodesInPlace(wchar_t *text) {
+ if(text == 0 || DBGetContactSettingByte(0, MODULE, "StripBBCodes", 1) == 0)
+ return;
+
+ int read = 0, write = 0;
+ int len = (int)wcslen(text);
+
+ while(read <= len) { // copy terminating null too
+ while(read <= len && text[read] != L'[') {
+ if(text[read] != text[write]) text[write] = text[read];
+ read++; write++;
+ }
+ if(read > len) break;
+
+ if(len - read >= 3 && (_wcsnicmp(text + read, L"[b]", 3) == 0 || _wcsnicmp(text + read, L"[i]", 3) == 0))
+ read += 3;
+ else if(len - read >= 4 && (_wcsnicmp(text + read, L"[/b]", 4) == 0 || _wcsnicmp(text + read, L"[/i]", 4) == 0))
+ read += 4;
+ else if(len - read >= 6 && (_wcsnicmp(text + read, L"[color", 6) == 0)) {
+ while(read < len && text[read] != L']') read++;
+ read++;// skip the ']'
+ } else if(len - read >= 8 && (_wcsnicmp(text + read, L"[/color]", 8) == 0))
+ read += 8;
+ else if(len - read >= 5 && (_wcsnicmp(text + read, L"[size", 5) == 0)) {
+ while(read < len && text[read] != L']') read++;
+ read++;// skip the ']'
+ } else if(len - read >= 7 && (_wcsnicmp(text + read, L"[/size]", 7) == 0))
+ read += 7;
+ else {
+ if(text[read] != text[write]) text[write] = text[read];
+ read++; write++;
+ }
+ }
+}
+
+INT_PTR OldCreatePopupA(WPARAM wParam, LPARAM lParam) {
+ POPUPDATA *pd_in = (POPUPDATA *)wParam;
+ PopupData *pd_out = (PopupData *)mir_calloc(sizeof(PopupData));
+
+ pd_out->cbSize = sizeof(PopupData);
+ pd_out->flags = PDF_UNICODE;
+ pd_out->pwzTitle = mir_a2u(pd_in->lpzContactName);
+ pd_out->pwzText = mir_a2u(pd_in->lpzText);
+ StripBBCodesInPlace(pd_out->pwzTitle);
+ StripBBCodesInPlace(pd_out->pwzText);
+
+ pd_out->hContact = pd_in->lchContact;
+ pd_out->hIcon = pd_in->lchIcon;
+ if(pd_in->colorBack == 0xffffffff) // that's the old #define for 'skinned bg'
+ pd_out->colorBack = pd_out->colorText = 0;
+ else {
+ pd_out->colorBack = pd_in->colorBack & 0xFFFFFF;
+ pd_out->colorText = pd_in->colorText & 0xFFFFFF;
+ }
+ pd_out->windowProc = pd_in->PluginWindowProc;
+ pd_out->opaque = pd_in->PluginData;
+ pd_out->timeout = 0;
+
+ lstPopupHistory.Add(pd_out->pwzTitle, pd_out->pwzText, time(0));
+
+ if (!DBGetContactSettingByte(0, MODULE, "Enabled", 1)) {
+ mir_free(pd_out->pwzTitle);
+ mir_free(pd_out->pwzText);
+ mir_free(pd_out);
+ return -1;
+ }
+
+ //MessageBox(0, pd_out->lpwzContactName, _T("CreatePopupA"), MB_OK);
+ PostMPMessage(MUM_CREATEPOPUP, 0, (LPARAM)pd_out);
+ return 0;
+}
+
+INT_PTR OldCreatePopupExA(WPARAM wParam, LPARAM lParam) {
+
+ POPUPDATAEX *pd_in = (POPUPDATAEX *)wParam;
+ PopupData *pd_out = (PopupData *)mir_calloc(sizeof(PopupData));
+
+ pd_out->cbSize = sizeof(PopupData);
+ pd_out->flags = PDF_UNICODE;
+ pd_out->pwzTitle = mir_a2u(pd_in->lpzContactName);
+ pd_out->pwzText = mir_a2u(pd_in->lpzText);
+ StripBBCodesInPlace(pd_out->pwzTitle);
+ StripBBCodesInPlace(pd_out->pwzText);
+
+ pd_out->hContact = pd_in->lchContact;
+ pd_out->hIcon = pd_in->lchIcon;
+ if(pd_in->colorBack == 0xffffffff) // that's the old #define for 'skinned bg'
+ pd_out->colorBack = pd_out->colorText = 0;
+ else {
+ pd_out->colorBack = pd_in->colorBack & 0xFFFFFF;
+ pd_out->colorText = pd_in->colorText & 0xFFFFFF;
+ }
+ pd_out->windowProc = pd_in->PluginWindowProc;
+ pd_out->opaque = pd_in->PluginData;
+ pd_out->timeout = pd_in->iSeconds;
+
+ lstPopupHistory.Add(pd_out->pwzTitle, pd_out->pwzText, time(0));
+ if (!DBGetContactSettingByte(0, MODULE, "Enabled", 1)) {
+ mir_free(pd_out->pwzTitle);
+ mir_free(pd_out->pwzText);
+ mir_free(pd_out);
+ return -1;
+ }
+
+ //MessageBox(0, pd_out->lpwzContactName, _T("CreatePopupExA"), MB_OK);
+ PostMPMessage(MUM_CREATEPOPUP, 0, (LPARAM)pd_out);
+ return 0;
+}
+
+INT_PTR OldCreatePopupW(WPARAM wParam, LPARAM lParam) {
+
+ POPUPDATAW *pd_in = (POPUPDATAW *)wParam;
+ PopupData *pd_out = (PopupData *)mir_calloc(sizeof(PopupData));
+
+ pd_out->cbSize = sizeof(PopupData);
+ pd_out->flags = PDF_UNICODE;
+ pd_out->pwzTitle = mir_wstrdup(pd_in->lpwzContactName);
+ pd_out->pwzText = mir_wstrdup(pd_in->lpwzText);
+ StripBBCodesInPlace(pd_out->pwzTitle);
+ StripBBCodesInPlace(pd_out->pwzText);
+
+ pd_out->hContact = pd_in->lchContact;
+ pd_out->hIcon = pd_in->lchIcon;
+ if(pd_in->colorBack == 0xffffffff) // that's the old #define for 'skinned bg'
+ pd_out->colorBack = pd_out->colorText = 0;
+ else {
+ pd_out->colorBack = pd_in->colorBack & 0xFFFFFF;
+ pd_out->colorText = pd_in->colorText & 0xFFFFFF;
+ }
+ pd_out->windowProc = pd_in->PluginWindowProc;
+ pd_out->opaque = pd_in->PluginData;
+ pd_out->timeout = pd_in->iSeconds;
+
+ lstPopupHistory.Add(pd_out->pwzTitle, pd_out->pwzText, time(0));
+ if (!DBGetContactSettingByte(0, MODULE, "Enabled", 1)) {
+ mir_free(pd_out->pwzTitle);
+ mir_free(pd_out->pwzText);
+ mir_free(pd_out);
+ return -1;
+ }
+
+ //MessageBox(0, pd_out->lpwzContactName, _T("CreatePopupW"), MB_OK);
+ PostMPMessage(MUM_CREATEPOPUP, 0, (LPARAM)pd_out);
+ return 0;
+}
+
+INT_PTR ChangeTextW(WPARAM wParam, LPARAM lParam)
+{
+ HWND hwndPop = (HWND)wParam;
+ wchar_t *newText = NEWWSTR_ALLOCA((wchar_t *)lParam);
+ StripBBCodesInPlace(newText);
+
+ if(IsWindow(hwndPop))
+ SendMessage(hwndPop, PUM_SETTEXT, 0, (LPARAM)newText);
+ else
+ mir_free(newText);
+ return 0;
+}
+
+INT_PTR ChangeTextA(WPARAM wParam, LPARAM lParam) {
+ HWND hwndPop = (HWND)wParam;
+ char *newText = (char *)lParam;
+ wchar_t* buff = mir_a2u(newText);
+ StripBBCodesInPlace(buff);
+
+ if(IsWindow(hwndPop))
+ SendMessage(hwndPop, PUM_SETTEXT, 0, (LPARAM)buff);
+
+ mir_free(buff);
+ return 0;
+}
+
+void ShowPopup(PopupData &pd_in)
+{
+ PopupData *pd_out = (PopupData *)mir_alloc(sizeof(PopupData));
+ *pd_out = pd_in;
+ if (pd_in.flags & PDF_UNICODE) {
+ pd_out->pwzTitle = mir_wstrdup(pd_in.pwzTitle);
+ pd_out->pwzText = mir_wstrdup(pd_in.pwzText);
+ } else {
+ pd_out->flags |= PDF_UNICODE;
+ pd_out->pwzTitle = mir_a2u(pd_in.pszTitle);
+ pd_out->pwzText = mir_a2u(pd_in.pszText);
+ }
+ StripBBCodesInPlace(pd_out->pwzTitle);
+ StripBBCodesInPlace(pd_out->pwzText);
+
+ lstPopupHistory.Add(pd_out->pwzTitle, pd_out->pwzText, time(0));
+
+ if (!DBGetContactSettingByte(0, MODULE, "Enabled", 1))
+ {
+ mir_free(pd_out->pwzTitle);
+ mir_free(pd_out->pwzText);
+ mir_free(pd_out);
+ }
+ else
+ PostMPMessage(MUM_CREATEPOPUP, 0, (LPARAM)pd_out);
+}
+
+INT_PTR GetContact(WPARAM wParam, LPARAM lParam) {
+ HWND hwndPop = (HWND)wParam;
+ HANDLE hContact;
+ if(GetCurrentThreadId() == message_pump_thread_id) {
+ SendMessage(hwndPop, PUM_GETCONTACT, (WPARAM)&hContact, 0);
+ } else {
+ HANDLE hEvent = CreateEvent(0, 0, 0, 0);
+ PostMessage(hwndPop, PUM_GETCONTACT, (WPARAM)&hContact, (LPARAM)hEvent);
+ MsgWaitForMultipleObjectsEx(1, &hEvent, INFINITE, 0, 0);
+ CloseHandle(hEvent);
+ }
+
+ return (INT_PTR)hContact;
+}
+
+INT_PTR GetOpaque(WPARAM wParam, LPARAM lParam) {
+ HWND hwndPop = (HWND)wParam;
+ void *data = 0;
+ if(GetCurrentThreadId() == message_pump_thread_id) {
+ SendMessage(hwndPop, PUM_GETOPAQUE, (WPARAM)&data, 0);
+ } else {
+ HANDLE hEvent = CreateEvent(0, 0, 0, 0);
+ PostMessage(hwndPop, PUM_GETOPAQUE, (WPARAM)&data, (LPARAM)hEvent);
+ MsgWaitForMultipleObjectsEx(1, &hEvent, INFINITE, 0, 0);
+ CloseHandle(hEvent);
+ }
+
+ return (INT_PTR)data;
+}
+
+INT_PTR IsSecondLineShown(WPARAM wParam, LPARAM lParam) {
+ return TRUE;
+}
+
+void UpdateMenu() {
+ CLISTMENUITEM mi = {0};
+ mi.cbSize = sizeof(CLISTMENUITEM);
+ mi.pszName = (char*)(DBGetContactSettingByte(0, MODULE, "Enabled", 1) == 1 ? LPGEN("Disable Popups") : LPGEN("Enable Popups"));
+ mi.flags = CMIM_NAME;// | CMIM_ICON;
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuToggleOnOff, (LPARAM)&mi);
+}
+
+INT_PTR PopupQuery(WPARAM wParam, LPARAM lParam) {
+ switch(wParam) {
+ case PUQS_ENABLEPOPUPS:
+ {
+ bool enabled = DBGetContactSettingByte(0, MODULE, "Enabled", 1) != 0;
+ if (!enabled) DBWriteContactSettingByte(0, MODULE, "Enabled", 1);
+ return !enabled;
+ }
+ break;
+ case PUQS_DISABLEPOPUPS:
+ {
+ bool enabled = DBGetContactSettingByte(0, MODULE, "Enabled", 1) != 0;
+ if (enabled) DBWriteContactSettingByte(0, MODULE, "Enabled", 0);
+ return enabled;
+ }
+ break;
+ case PUQS_GETSTATUS:
+ return DBGetContactSettingByte(0, MODULE, "Enabled", 1);
+ default:
+ return 1;
+ }
+ UpdateMenu();
+ return 0;
+}
+
+INT_PTR TogglePopups(WPARAM wParam, LPARAM lParam) {
+ BYTE val = DBGetContactSettingByte(0, MODULE, "Enabled", 1);
+ DBWriteContactSettingByte(0, MODULE, "Enabled", !val);
+ UpdateMenu();
+ return 0;
+}
+
+INT_PTR PopupChangeA(WPARAM wParam, LPARAM lParam) {
+ HWND hwndPop = (HWND)wParam;
+ POPUPDATAEX *pd_in = (POPUPDATAEX *)lParam;
+
+ if(IsWindow(hwndPop)) {
+ PopupData pd_out;
+ pd_out.cbSize = sizeof(PopupData);
+ pd_out.flags = PDF_UNICODE;
+
+ pd_out.pwzTitle = mir_a2u(pd_in->lpzContactName);
+ pd_out.pwzText = mir_a2u(pd_in->lpzText);
+ StripBBCodesInPlace(pd_out.pwzTitle);
+ StripBBCodesInPlace(pd_out.pwzText);
+
+ pd_out.hContact = pd_in->lchContact;
+ pd_out.hIcon = pd_in->lchIcon;
+ if(pd_in->colorBack == 0xffffffff) // that's the old #define for 'skinned bg'
+ pd_out.colorBack = pd_out.colorText = 0;
+ else {
+ pd_out.colorBack = pd_in->colorBack & 0xFFFFFF;
+ pd_out.colorText = pd_in->colorText & 0xFFFFFF;
+ }
+ pd_out.colorBack = pd_in->colorBack;
+ pd_out.colorText = pd_in->colorText;
+ pd_out.windowProc = pd_in->PluginWindowProc;
+ pd_out.opaque = pd_in->PluginData;
+ pd_out.timeout = pd_in->iSeconds;
+
+ lstPopupHistory.Add(pd_out.pwzTitle, pd_out.pwzText, time(0));
+
+ SendMessage(hwndPop, PUM_CHANGE, 0, (LPARAM)&pd_out);
+ }
+ return 0;
+}
+
+INT_PTR PopupChangeW(WPARAM wParam, LPARAM lParam) {
+ HWND hwndPop = (HWND)wParam;
+ POPUPDATAW *pd_in = (POPUPDATAW *)lParam;
+
+ if(IsWindow(hwndPop)) {
+ PopupData pd_out;
+ pd_out.cbSize = sizeof(PopupData);
+ pd_out.flags = PDF_UNICODE;
+
+ pd_out.pwzTitle = mir_wstrdup(pd_in->lpwzContactName);
+ pd_out.pwzText = mir_wstrdup(pd_in->lpwzText);
+ StripBBCodesInPlace(pd_out.pwzTitle);
+ StripBBCodesInPlace(pd_out.pwzText);
+
+ pd_out.hContact = pd_in->lchContact;
+ pd_out.hIcon = pd_in->lchIcon;
+ if(pd_in->colorBack == 0xffffffff) // that's the old #define for 'skinned bg'
+ pd_out.colorBack = pd_out.colorText = 0;
+ else {
+ pd_out.colorBack = pd_in->colorBack & 0xFFFFFF;
+ pd_out.colorText = pd_in->colorText & 0xFFFFFF;
+ }
+ pd_out.colorBack = pd_in->colorBack;
+ pd_out.colorText = pd_in->colorText;
+ pd_out.windowProc = pd_in->PluginWindowProc;
+ pd_out.opaque = pd_in->PluginData;
+ pd_out.timeout = pd_in->iSeconds;
+
+ lstPopupHistory.Add(pd_out.pwzTitle, pd_out.pwzText, time(0));
+
+ SendMessage(hwndPop, PUM_CHANGE, 0, (LPARAM)&pd_out);
+ }
+ return 0;
+}
+
+INT_PTR ShowMessage(WPARAM wParam, LPARAM lParam) {
+ if (!DBGetContactSettingByte(0, MODULE, "Enabled", 1)) return 0;
+
+ POPUPDATAT pd = {0};
+ _tcscpy(pd.lptzContactName, lParam == SM_WARNING ? _T("Warning") : _T("Notification"));
+ pd.lchIcon = LoadIcon(0, lParam == SM_WARNING ? IDI_WARNING : IDI_INFORMATION);
+ TCHAR *buff = mir_a2t((char *)wParam);
+ _tcscpy(pd.lptzText, buff); pd.lptzText[MAX_SECONDLINE-1] = 0;
+ mir_free(buff);
+
+ CallService(MS_POPUP_ADDPOPUPT, (WPARAM)&pd, 0);
+
+ return 0;
+}
+
+INT_PTR ShowMessageW(WPARAM wParam, LPARAM lParam) {
+ if (!DBGetContactSettingByte(0, MODULE, "Enabled", 1)) return 0;
+
+ POPUPDATAW pd = {0};
+ wcscpy(pd.lpwzContactName, lParam == SM_WARNING ? L"Warning" : L"Notification");
+ pd.lchIcon = LoadIcon(0, lParam == SM_WARNING ? IDI_WARNING : IDI_INFORMATION);
+ wcsncpy(pd.lpwzText, (wchar_t *)wParam, MAX_SECONDLINE);
+
+ CallService(MS_POPUP_ADDPOPUPW, (WPARAM)&pd, 0);
+
+ return 0;
+}
+
+//=====PopUp/ShowHistory
+//extern BOOL CALLBACK DlgProcHistLstOpts(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+INT_PTR PopUp_ShowHistory(WPARAM wParam, LPARAM lParam)
+{
+ if (!hHistoryWindow) {
+ hHistoryWindow = CreateDialog(hInst, MAKEINTRESOURCE(IDD_LST_HISTORY), NULL, DlgProcHistLst);
+ }
+ ShowWindow(hHistoryWindow, SW_SHOW);
+ return 0;
+}
+
+int num_classes = 0;
+POPUPCLASS *classes = 0;
+
+INT_PTR RegisterPopupClass(WPARAM wParam, LPARAM lParam)
+{
+ classes = (POPUPCLASS *)mir_realloc(classes, sizeof(POPUPCLASS) * (num_classes + 1));
+ memcpy(classes + num_classes, (PVOID)lParam, sizeof(POPUPCLASS));
+ POPUPCLASS *pc = classes + num_classes;
+ num_classes++;
+
+ pc->pszName = mir_strdup(pc->pszName);
+ if(pc->flags & PCF_UNICODE)
+ pc->pwszDescription = mir_wstrdup(pc->pwszDescription);
+ else
+ pc->pszDescription = mir_strdup(pc->pszDescription);
+
+ char setting[256];
+ mir_snprintf(setting, 256, "%s/Timeout", pc->pszName);
+ pc->iSeconds = DBGetContactSettingWord(0, MODULE, setting, pc->iSeconds);
+ if(pc->iSeconds == (WORD)-1) pc->iSeconds = -1;
+ mir_snprintf(setting, 256, "%s/TextCol", pc->pszName);
+ pc->colorText = (COLORREF)DBGetContactSettingDword(0, MODULE, setting, (DWORD)pc->colorText);
+ mir_snprintf(setting, 256, "%s/BgCol", pc->pszName);
+ pc->colorBack = (COLORREF)DBGetContactSettingDword(0, MODULE, setting, (DWORD)pc->colorBack);
+
+ return 0;
+}
+
+INT_PTR CreateClassPopup(WPARAM wParam, LPARAM lParam)
+{
+ POPUPDATACLASS *pdc = (POPUPDATACLASS *)lParam;
+ if(pdc->cbSize < sizeof(POPUPDATACLASS)) return 1;
+
+ POPUPCLASS *pc = 0;
+ if(wParam)
+ pc = (POPUPCLASS *)wParam;
+ else {
+ for(int i = 0; i < num_classes; i++) {
+ if(strcmp(classes[i].pszName, pdc->pszClassName) == 0) {
+ pc = &classes[i];
+ break;
+ }
+ }
+ }
+ if(pc) {
+ PopupData pd = {sizeof(PopupData)};
+ if(pc->flags & PCF_UNICODE) pd.flags |= PDF_UNICODE;
+ pd.colorBack = pc->colorBack;
+ pd.colorText = pc->colorText;
+ pd.hIcon = pc->hIcon;
+ pd.timeout = pc->iSeconds;
+ pd.windowProc = pc->PluginWindowProc;
+
+ pd.hContact = pdc->hContact;
+ pd.opaque = pdc->PluginData;
+ pd.pszTitle = (char *)pdc->pszTitle;
+ pd.pszText = (char *)pdc->pszText;
+
+ ShowPopup(pd);
+ }
+ return 0;
+}
+
+int PrebuildMenu(WPARAM wParam, LPARAM lParam) {
+ return 0;
+}
+
+HANDLE hEventBuildMenu;
+
+void InitServices()
+{
+ int i = 0;
+ hService[i++] = CreateServiceFunction(MS_POPUP_REGISTERCLASS, RegisterPopupClass);
+ hService[i++] = CreateServiceFunction(MS_POPUP_ADDPOPUPCLASS, CreateClassPopup);
+ hService[i++] = CreateServiceFunction(MS_POPUP_ADDPOPUP, OldCreatePopupA);
+ hService[i++] = CreateServiceFunction(MS_POPUP_ADDPOPUPEX, OldCreatePopupExA);
+ hService[i++] = CreateServiceFunction(MS_POPUP_ADDPOPUPW, OldCreatePopupW);
+ hService[i++] = CreateServiceFunction(MS_POPUP_CHANGETEXTW, ChangeTextW);
+ hService[i++] = CreateServiceFunction(MS_POPUP_CHANGETEXT, ChangeTextA);
+ hService[i++] = CreateServiceFunction(MS_POPUP_CHANGE, PopupChangeA);
+ hService[i++] = CreateServiceFunction(MS_POPUP_CHANGEW, PopupChangeW);
+ hService[i++] = CreateServiceFunction(MS_POPUP_GETCONTACT, GetContact);
+ hService[i++] = CreateServiceFunction(MS_POPUP_GETPLUGINDATA, GetOpaque);
+ hService[i++] = CreateServiceFunction(MS_POPUP_ISSECONDLINESHOWN, IsSecondLineShown);
+ hService[i++] = CreateServiceFunction(MS_POPUP_QUERY, PopupQuery);
+
+ hService[i++] = CreateServiceFunction(MS_POPUP_SHOWMESSAGE, ShowMessage);
+ hService[i++] = CreateServiceFunction(MS_POPUP_SHOWMESSAGE"W", ShowMessageW);
+
+ hService[i++] = CreateServiceFunction(MS_POPUP_SHOWHISTORY, PopUp_ShowHistory);
+ hService[i++] = CreateServiceFunction("PopUp/ToggleEnabled", TogglePopups);
+
+ hService[i++] = CreateServiceFunction("YAPP/RegisterClass", RegisterPopupClass);
+ hService[i++] = CreateServiceFunction("YAPP/ClassInstance", CreateClassPopup);
+
+ CLISTMENUITEM mi = {0};
+
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIM_ALL;
+
+ mi.position = 500010000;
+ mi.pszPopupName = LPGEN("PopUps");
+
+ hiPopupHistory = LoadIcon(hInst, MAKEINTRESOURCE(IDI_POPUP_HISTORY));
+ mi.hIcon = hiPopupHistory;
+ mi.pszService= MS_POPUP_SHOWHISTORY;
+ mi.pszName = LPGEN("Popup History");
+ hMenuShowHistory = Menu_AddMainMenuItem(&mi);
+
+ mi.hIcon = NULL;
+ mi.pszService = "PopUp/ToggleEnabled";
+ mi.pszName = (char*)(DBGetContactSettingByte(0, MODULE, "Enabled", 1) ?
+ LPGEN("Disable Popups") : LPGEN("Enable Popups"));
+ hMenuToggleOnOff = Menu_AddMainMenuItem(&mi);
+
+ hEventBuildMenu = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, PrebuildMenu);
+}
+
+void DeinitServices() {
+ int i;
+ for(i = 0; i < num_classes; i++) {
+ mir_free(classes[i].pszName);
+ mir_free(classes[i].pszDescription);
+ }
+ mir_free(classes); num_classes = 0;
+
+ UnhookEvent(hEventBuildMenu);
+
+ for(i = 0; i < NUM_SERVICES; i++)
+ if(hService[i]) DestroyServiceFunction(hService[i]);
+}
diff --git a/plugins/YAPP/src/services.h b/plugins/YAPP/src/services.h
new file mode 100644
index 0000000000..8243b0ba8b
--- /dev/null
+++ b/plugins/YAPP/src/services.h
@@ -0,0 +1,10 @@
+#ifndef _SERVICES_INC
+#define _SERVICES_INC
+
+void InitServices();
+void DeinitServices();
+
+extern int num_classes;
+extern POPUPCLASS *classes;
+
+#endif
diff --git a/plugins/YAPP/src/version.h b/plugins/YAPP/src/version.h
new file mode 100644
index 0000000000..4118cc9091
--- /dev/null
+++ b/plugins/YAPP/src/version.h
@@ -0,0 +1,24 @@
+#ifndef __VERSION_H_INCLUDED
+#define __VERSION_H_INCLUDED
+
+#define __MAJOR_VERSION 0
+#define __MINOR_VERSION 5
+#define __RELEASE_NUM 0
+#define __BUILD_NUM 10
+
+#define __FILEVERSION_STRING __MAJOR_VERSION,__MINOR_VERSION,__RELEASE_NUM,__BUILD_NUM
+#define __FILEVERSION_STRING_DOTS __MAJOR_VERSION.__MINOR_VERSION.__RELEASE_NUM.__BUILD_NUM
+#define __STRINGIFY(x) #x
+#define __VERSION_STRING __STRINGIFY(__FILEVERSION_STRING_DOTS)
+
+#define __DESC "Yet Another Popup Plugin - Provides popup notification window services (unicode and ansi) to other plugins"
+#define __AUTHOR "Scott Ellis"
+#define __AUTHOREMAIL "mail@scottellis.com.au"
+#define __COPYRIGHT "© 2005,2006 Scott Ellis"
+#define __AUTHORWEB "http://www.scottellis.com.au"
+
+#define __PLUGIN_NAME "YAPP"
+
+#define __FILENAME "yapp.dll"
+
+#endif //__VERSION_H_INCLUDED
diff --git a/plugins/YAPP/src/yapp.cpp b/plugins/YAPP/src/yapp.cpp
new file mode 100644
index 0000000000..11067040b2
--- /dev/null
+++ b/plugins/YAPP/src/yapp.cpp
@@ -0,0 +1,241 @@
+// popups2.cpp : Defines the entry point for the DLL application.
+//
+
+#include "common.h"
+#include "yapp.h"
+#include "version.h"
+#include "message_pump.h"
+#include "options.h"
+#include "popwin.h"
+#include "notify.h"
+
+#include "yapp_history.h" //to be able to update the renderer
+
+HMODULE hInst = 0;
+
+MNOTIFYLINK *notifyLink = 0;
+
+// used to work around a bug in neweventnotify and others with the address passed in the GetPluginData function
+bool ignore_gpd_passed_addy = false;
+
+FontID font_id_firstline = {0}, font_id_secondline = {0}, font_id_time = {0};
+ColourID colour_id_bg = {0}, colour_id_border = {0}, colour_id_sidebar = {0}, colour_id_titleunderline = {0};
+FontIDW font_id_firstlinew = {0}, font_id_secondlinew = {0}, font_id_timew = {0};
+ColourIDW colour_id_bgw = {0}, colour_id_borderw = {0}, colour_id_sidebarw = {0}, colour_id_titleunderlinew = {0};
+
+COLORREF colBg = GetSysColor(COLOR_3DSHADOW);
+HFONT hFontFirstLine = 0, hFontSecondLine = 0, hFontTime = 0;
+COLORREF colFirstLine = RGB(255, 0, 0), colSecondLine = 0, colTime = RGB(0, 0, 255), colBorder = RGB(0, 0, 0),
+ colSidebar = RGB(128, 128, 128), colTitleUnderline = GetSysColor(COLOR_3DSHADOW);
+int hLangpack;
+
+PLUGININFOEX pluginInfo={
+ sizeof(PLUGININFOEX),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESC,
+ __AUTHOR,
+ __AUTHOREMAIL,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE,
+ { 0xefd15f16, 0x7ae4, 0x40d7, { 0xa8, 0xe3, 0xa4, 0x11, 0xed, 0x74, 0x7b, 0xd5 } } // {EFD15F16-7AE4-40d7-A8E3-A411ED747BD5}
+};
+
+
+
+
+extern "C" BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
+{
+ hInst = hModule;
+ DisableThreadLibraryCalls(hInst);
+ return TRUE;
+}
+
+extern "C" YAPP_API PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion)
+{
+ return &pluginInfo;
+}
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_POPUPS, MIID_LAST};
+
+int ReloadFont(WPARAM wParam, LPARAM lParam)
+{
+
+ if(ServiceExists(MS_FONT_GETW)) {
+ LOGFONTW log_font;
+ if(hFontFirstLine) DeleteObject(hFontFirstLine);
+ colFirstLine = CallService(MS_FONT_GETW, (WPARAM)&font_id_firstlinew, (LPARAM)&log_font);
+ hFontFirstLine = CreateFontIndirectW(&log_font);
+ if(hFontSecondLine) DeleteObject(hFontSecondLine);
+ colSecondLine = CallService(MS_FONT_GETW, (WPARAM)&font_id_secondlinew, (LPARAM)&log_font);
+ hFontSecondLine = CreateFontIndirectW(&log_font);
+ if(hFontTime) DeleteObject(hFontTime);
+ colTime = CallService(MS_FONT_GETW, (WPARAM)&font_id_timew, (LPARAM)&log_font);
+ hFontTime = CreateFontIndirectW(&log_font);
+
+ colBg = CallService(MS_COLOUR_GETW, (WPARAM)&colour_id_bgw, 0);
+ colBorder = CallService(MS_COLOUR_GETW, (WPARAM)&colour_id_borderw, 0);
+ colSidebar = CallService(MS_COLOUR_GETW, (WPARAM)&colour_id_sidebarw, 0);
+ colTitleUnderline = CallService(MS_COLOUR_GETW, (WPARAM)&colour_id_titleunderlinew, 0);
+ } else
+
+ {
+ LOGFONTA log_font;
+ if(hFontFirstLine) DeleteObject(hFontFirstLine);
+ colFirstLine = CallService(MS_FONT_GET, (WPARAM)&font_id_firstline, (LPARAM)&log_font);
+ hFontFirstLine = CreateFontIndirectA(&log_font);
+ if(hFontSecondLine) DeleteObject(hFontSecondLine);
+ colSecondLine = CallService(MS_FONT_GET, (WPARAM)&font_id_secondline, (LPARAM)&log_font);
+ hFontSecondLine = CreateFontIndirectA(&log_font);
+ if(hFontTime) DeleteObject(hFontTime);
+ colTime = CallService(MS_FONT_GET, (WPARAM)&font_id_time, (LPARAM)&log_font);
+ hFontTime = CreateFontIndirectA(&log_font);
+
+ colBg = CallService(MS_COLOUR_GET, (WPARAM)&colour_id_bg, 0);
+ colBorder = CallService(MS_COLOUR_GET, (WPARAM)&colour_id_border, 0);
+ colSidebar = CallService(MS_COLOUR_GET, (WPARAM)&colour_id_sidebar, 0);
+ colTitleUnderline = CallService(MS_COLOUR_GET, (WPARAM)&colour_id_titleunderline, 0);
+ }
+
+ return 0;
+}
+
+HANDLE hEventReloadFont = 0;
+
+int ModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ MNotifyGetLink();
+
+ if (ServiceExists(MS_HPP_EG_WINDOW))
+ lstPopupHistory.SetRenderer(RENDER_HISTORYPP);
+
+ font_id_firstlinew.cbSize = sizeof(FontIDW);
+ font_id_firstlinew.flags = FIDF_ALLOWEFFECTS;
+ _tcscpy(font_id_firstlinew.group, _T("Popups"));
+ _tcscpy(font_id_firstlinew.name, _T("First line"));
+ strcpy(font_id_firstlinew.dbSettingsGroup, MODULE);
+ strcpy(font_id_firstlinew.prefix, "FontFirst");
+ _tcscpy(font_id_firstlinew.backgroundGroup, _T("Popups"));
+ _tcscpy(font_id_firstlinew.backgroundName, _T("Background"));
+ font_id_firstlinew.order = 0;
+ FontRegisterT(&font_id_firstlinew);
+
+ font_id_secondlinew.cbSize = sizeof(FontIDW);
+ font_id_secondlinew.flags = FIDF_ALLOWEFFECTS;
+ _tcscpy(font_id_secondlinew.group, _T("Popups"));
+ _tcscpy(font_id_secondlinew.name, _T("Second line"));
+ strcpy(font_id_secondlinew.dbSettingsGroup, MODULE);
+ strcpy(font_id_secondlinew.prefix, "FontSecond");
+ _tcscpy(font_id_secondlinew.backgroundGroup, _T("Popups"));
+ _tcscpy(font_id_secondlinew.backgroundName, _T("Background"));
+ font_id_secondlinew.order = 1;
+ FontRegisterT(&font_id_secondlinew);
+
+ font_id_timew.cbSize = sizeof(FontIDW);
+ font_id_timew.flags = FIDF_ALLOWEFFECTS;
+ _tcscpy(font_id_timew.group, _T("Popups"));
+ _tcscpy(font_id_timew.name, _T("Time"));
+ strcpy(font_id_timew.dbSettingsGroup, MODULE);
+ strcpy(font_id_timew.prefix, "FontTime");
+ _tcscpy(font_id_timew.backgroundGroup, _T("Popups"));
+ _tcscpy(font_id_timew.backgroundName, _T("Background"));
+ font_id_timew.order = 2;
+ FontRegisterT(&font_id_timew);
+
+ colour_id_bgw.cbSize = sizeof(ColourIDW);
+ _tcscpy(colour_id_bgw.group, _T("Popups"));
+ _tcscpy(colour_id_bgw.name, _T("Background"));
+ strcpy(colour_id_bgw.dbSettingsGroup, MODULE);
+ strcpy(colour_id_bgw.setting, "ColourBg");
+ colour_id_bgw.defcolour = GetSysColor(COLOR_3DSHADOW);
+ colour_id_bgw.order = 0;
+ ColourRegisterT(&colour_id_bgw);
+
+ colour_id_borderw.cbSize = sizeof(ColourIDW);
+ _tcscpy(colour_id_borderw.group, _T("Popups"));
+ _tcscpy(colour_id_borderw.name, _T("Border"));
+ strcpy(colour_id_borderw.dbSettingsGroup, MODULE);
+ strcpy(colour_id_borderw.setting, "ColourBorder");
+ colour_id_borderw.defcolour = RGB(0, 0, 0);
+ colour_id_borderw.order = 1;
+ ColourRegisterT(&colour_id_borderw);
+
+ colour_id_sidebarw.cbSize = sizeof(ColourIDW);
+ _tcscpy(colour_id_sidebarw.group, _T("Popups"));
+ _tcscpy(colour_id_sidebarw.name, _T("Sidebar"));
+ strcpy(colour_id_sidebarw.dbSettingsGroup, MODULE);
+ strcpy(colour_id_sidebarw.setting, "ColourSidebar");
+ colour_id_sidebarw.defcolour = RGB(128, 128, 128);
+ colour_id_sidebarw.order = 2;
+ ColourRegisterT(&colour_id_sidebarw);
+
+ colour_id_titleunderlinew.cbSize = sizeof(ColourIDW);
+ _tcscpy(colour_id_titleunderlinew.group, _T("Popups"));
+ _tcscpy(colour_id_titleunderlinew.name, _T("Title underline"));
+ strcpy(colour_id_titleunderlinew.dbSettingsGroup, MODULE);
+ strcpy(colour_id_titleunderlinew.setting, "ColourTitleUnderline");
+ colour_id_titleunderlinew.defcolour = GetSysColor(COLOR_3DSHADOW);
+ colour_id_titleunderlinew.order = 3;
+ ColourRegisterT(&colour_id_titleunderlinew);
+
+ ReloadFont(0, 0);
+
+ hEventReloadFont = HookEvent(ME_FONT_RELOAD, ReloadFont);
+
+ LoadModuleDependentOptions();
+
+ if(GetModuleHandle(_T("neweventnotify")))
+ ignore_gpd_passed_addy = true;
+
+ return 0;
+}
+
+int PreShutdown(WPARAM wParam, LPARAM lParam) {
+ DeinitMessagePump();
+ DeinitNotify();
+ return 0;
+}
+
+HANDLE hEventPreShutdown, hEventModulesLoaded;
+
+extern "C" int YAPP_API Load(void) {
+
+ mir_getLP(&pluginInfo);
+
+ InitMessagePump();
+ InitOptions();
+ InitNotify();
+
+ hEventPreShutdown = HookEvent(ME_SYSTEM_PRESHUTDOWN, PreShutdown);
+ hEventModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded);
+
+ /*
+ // test popup classes
+ PopupClass test = {0};
+ test.cbSize = sizeof(test);
+ test.flags = PCF_TCHAR;
+ test.hIcon = LoadIcon(0, IDI_WARNING);
+ test.colorBack = RGB(0, 0, 0);
+ test.colorText = RGB(255, 255, 255);
+ test.iSeconds = 10;
+ test.ptszDescription = TranslateT("Test popup class");
+ test.pszName = "popup/testclass";
+ CallService(MS_POPUP_REGISTERCLASS, 0, (WPARAM)&test);
+ */
+
+ return 0;
+}
+
+extern "C" int YAPP_API Unload()
+{
+ if(hEventReloadFont)
+ UnhookEvent(hEventReloadFont);
+ UnhookEvent(hEventPreShutdown);
+ UnhookEvent(hEventModulesLoaded);
+ DeinitNotify();
+ DeleteObject(hFontFirstLine);
+ DeleteObject(hFontSecondLine);
+ DeleteObject(hFontTime);
+ return 0;
+}
diff --git a/plugins/YAPP/src/yapp.h b/plugins/YAPP/src/yapp.h
new file mode 100644
index 0000000000..de86e26295
--- /dev/null
+++ b/plugins/YAPP/src/yapp.h
@@ -0,0 +1,12 @@
+// The following ifdef block is the standard way of creating macros which make exporting
+// from a DLL simpler. All files within this DLL are compiled with the POPUPS2_EXPORTS
+// symbol defined on the command line. this symbol should not be defined on any project
+// that uses this DLL. This way any other project whose source files include this file see
+// POPUPS2_API functions as being imported from a DLL, whereas this DLL sees symbols
+// defined with this macro as being exported.
+#ifdef YAPP_EXPORTS
+#define YAPP_API __declspec(dllexport)
+#else
+#define YAPP_API __declspec(dllimport)
+#endif
+
diff --git a/plugins/YAPP/src/yapp_history.cpp b/plugins/YAPP/src/yapp_history.cpp
new file mode 100644
index 0000000000..d6b0c4b114
--- /dev/null
+++ b/plugins/YAPP/src/yapp_history.cpp
@@ -0,0 +1,87 @@
+#include "common.h"
+#include "yapp_history.h"
+
+PopupHistoryList::PopupHistoryList(int renderer)
+{
+ this->renderer = renderer;
+ size = HISTORY_SIZE; //fixed size (at least for now)
+ historyData = (PopupHistoryData *) malloc(size * sizeof(PopupHistoryData)); //alloc space for data
+ count = 0;
+}
+
+PopupHistoryList::~PopupHistoryList()
+{
+ Clear(); //clear the data strings
+ free(historyData); //deallocate the data list
+}
+
+void PopupHistoryList::Clear()
+{
+ int i;
+ for (i = 0; i < count; i++)
+ {
+ DeleteData(i);
+ }
+ count = 0;
+}
+
+void PopupHistoryList::RemoveItem(int index)
+{
+ int i;
+ DeleteData(index); //free the mem for that particular item
+ for (i = index + 1; i < count; i++)
+ {
+ historyData[i - 1] = historyData[i]; //shift all items to the left
+ }
+}
+
+void PopupHistoryList::DeleteData(int index)
+{
+ PopupHistoryData *item = &historyData[index];
+ mir_free(item->titleT);
+ mir_free(item->messageT);
+ item->timestamp = 0; //invalidate item
+ item->title = NULL;
+ item->message = NULL;
+ item->flags = 0;
+}
+
+void PopupHistoryList::AddItem(PopupHistoryData item)
+{
+ if (count >= size)
+ {
+ RemoveItem(0); //remove first element - the oldest
+ count--; //it will be inc'ed later
+ }
+ historyData[count++] = item; //item has it's relevant strings dupped()
+ RefreshPopupHistory(hHistoryWindow, GetRenderer());
+}
+
+void PopupHistoryList::Add(char *title, char *message, time_t timestamp)
+{
+ PopupHistoryData item = {0}; //create a history item
+ item.timestamp = timestamp;
+ item.title = mir_strdup(title);
+ item.message = mir_strdup(message);
+ AddItem(item); //add it (flags = 0)
+}
+
+void PopupHistoryList::Add(wchar_t *title, wchar_t *message, time_t timestamp)
+{
+ PopupHistoryData item = {0}; //create an unicode history item
+ item.flags = PHDF_UNICODE; //mark it as unicode
+ item.timestamp = timestamp;
+ item.titleT = mir_u2t(title);
+ item.messageT = mir_u2t(message);
+ AddItem(item); //add it
+}
+
+PopupHistoryData *PopupHistoryList::Get(int index)
+{
+ if ((index < 0) || (index >= count)) //a bit of sanity check
+ {
+ return NULL;
+ }
+
+ return &historyData[index];
+}
diff --git a/plugins/YAPP/src/yapp_history.h b/plugins/YAPP/src/yapp_history.h
new file mode 100644
index 0000000000..d527bc47f4
--- /dev/null
+++ b/plugins/YAPP/src/yapp_history.h
@@ -0,0 +1,96 @@
+#ifndef __yapp_history_h__
+#define __yapp_history_h__
+
+#include "m_ieview.h" //need this for special renderers
+
+/****HISTORY ++ STUFF ***/
+//there's no include file for h++ yet
+#ifndef MS_HPP_EG_WINDOW
+#define MS_HPP_EG_WINDOW "History++/ExtGrid/NewWindow"
+#endif
+
+#ifndef MS_HPP_EG_EVENT
+#define MS_HPP_EG_EVENT "History++/ExtGrid/Event"
+#endif
+
+#ifndef MS_HPP_EG_NAVIGATE
+#define MS_HPP_EG_NAVIGATE "History++/ExtGrid/Navigate"
+#endif
+
+#ifndef MS_HPP_EG_OPTIONSCHANGED
+#define MS_HPP_EG_OPTIONSCHANGED "History++/ExtGrid/OptionsChanged"
+#endif
+/************************/
+
+
+
+#define HISTORY_SIZE 200 //number of popup history items
+
+#define PHDF_UNICODE 1
+
+#define POPUPMENU_TITLE 100
+#define POPUPMENU_MESSAGE 101
+#define POPUPMENU_TIMESTAMP 102
+
+#define RENDER_DEFAULT 0x00000
+#define RENDER_HISTORYPP 0x00001
+#define RENDER_IEVIEW 0x00002
+
+struct PopupHistoryData{
+ DWORD flags; //PHDF_* flags
+ union{
+ char *message;
+ wchar_t *messageW;
+ TCHAR *messageT;
+ };
+ union{
+ char *title;
+ wchar_t *titleW;
+ TCHAR *titleT;
+ };
+ time_t timestamp;
+};
+
+class PopupHistoryList{
+ private:
+ PopupHistoryData *historyData; //historyData[0] - oldest, historyData[size - 1] - newest
+ int count;
+ int size;
+ int renderer;
+
+ void DeleteData(int index);
+ void AddItem(PopupHistoryData item); //adds a PopupHistoryData item
+ void RemoveItem(int index);
+
+ public:
+ PopupHistoryList(int renderer = RENDER_DEFAULT);
+ ~PopupHistoryList();
+
+ int GetRenderer() { return renderer; }
+ void SetRenderer(int newRenderer) { renderer = newRenderer; }
+
+ void Add(char *title, char *message, time_t timestamp);
+ void Add(wchar_t *title, wchar_t *message, time_t timestamp);
+
+ PopupHistoryData *Get(int index);
+
+ void Clear();
+ int Count() { return count; }
+ int Size() { return size; }
+};
+
+/*Shows a history with the last popups.
+Useful if you've missed a popup when it appeared.
+wParam - 0
+lParam - 0
+*/
+#define MS_POPUP_SHOWHISTORY "PopUp/ShowHistory"
+
+extern PopupHistoryList lstPopupHistory; //defined in main.cpp
+extern HWND hHistoryWindow; //the history window
+extern HICON hiPopupHistory;
+void RefreshPopupHistory(HWND hWnd, int renderer);
+
+INT_PTR CALLBACK DlgProcHistLst(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+#endif //__popup_history_h__
diff --git a/plugins/YAPP/src/yapp_history_dlg.cpp b/plugins/YAPP/src/yapp_history_dlg.cpp
new file mode 100644
index 0000000000..534af1fe0c
--- /dev/null
+++ b/plugins/YAPP/src/yapp_history_dlg.cpp
@@ -0,0 +1,743 @@
+#include "common.h"
+#include "resource.h"
+#include "yapp_history.h"
+
+//************ Some helper resize stuff ******************
+
+#define MIN_HISTORY_WIDTH 540
+#define MIN_HISTORY_HEIGHT 300
+
+#define GAP_SIZE 2
+
+#define ANCHOR_LEFT 0x000001
+#define ANCHOR_RIGHT 0x000002
+#define ANCHOR_TOP 0x000004
+#define ANCHOR_BOTTOM 0x000008
+#define ANCHOR_ALL ANCHOR_LEFT | ANCHOR_RIGHT | ANCHOR_TOP | ANCHOR_BOTTOM
+
+WNDPROC oldPopupsListProc = NULL;
+
+HWND hHistoryWindow = 0; //the history window
+HICON hiPopupHistory; //popup history icon
+PopupHistoryList lstPopupHistory; //defined in main.cpp
+
+const TCHAR *szHistoryColumns[] = {_T("Title"), _T("Message"), _T("Timestamp")}; //need to make sure that the string and size vectors have the same number of elements
+const int cxHistoryColumns[] = {100, 450, 115};
+const int cHistoryColumns = sizeof(szHistoryColumns) / sizeof(szHistoryColumns[0]);
+
+struct PopupHistoryWindowData{
+ HWND hIEView;
+};
+
+void ScreenToClient(HWND hWnd, LPRECT rect)
+{
+ POINT pt;
+ int cx = rect->right - rect->left;
+ int cy = rect->bottom - rect->top;
+ pt.x = rect->left;
+ pt.y = rect->top;
+ ScreenToClient(hWnd, &pt);
+ rect->left = pt.x;
+ rect->top = pt.y;
+ rect->right = pt.x + cx;
+ rect->bottom = pt.y + cy;
+}
+
+RECT AnchorCalcPos(HWND window, const RECT *rParent, const WINDOWPOS *parentPos, int anchors)
+{
+ RECT rChild;
+ RECT rTmp;
+
+ GetWindowRect(window, &rChild);
+ ScreenToClient(parentPos->hwnd, &rChild);
+
+ int cx = rParent->right - rParent->left;
+ int cy = rParent->bottom - rParent->top;
+ if ((cx == parentPos->cx) && (cy == parentPos->cy))
+ {
+ return rChild;
+ }
+ if (parentPos->flags & SWP_NOSIZE)
+ {
+ return rChild;
+ }
+
+ rTmp.left = parentPos->x - rParent->left;
+ rTmp.right = (parentPos->x + parentPos->cx) - rParent->right;
+ rTmp.bottom = (parentPos->y + parentPos->cy) - rParent->bottom;
+ rTmp.top = parentPos->y - rParent->top;
+
+ cx = (rTmp.left) ? -rTmp.left : rTmp.right;
+ cy = (rTmp.top) ? -rTmp.top : rTmp.bottom;
+
+ rChild.right += cx;
+ rChild.bottom += cy;
+ //expanded the window accordingly, now we need to enforce the anchors
+ if ((anchors & ANCHOR_LEFT) && (!(anchors & ANCHOR_RIGHT)))
+ {
+ rChild.right -= cx;
+ }
+ if ((anchors & ANCHOR_TOP) && (!(anchors & ANCHOR_BOTTOM)))
+ {
+ rChild.bottom -= cy;
+ }
+ if ((anchors & ANCHOR_RIGHT) && (!(anchors & ANCHOR_LEFT)))
+ {
+ rChild.left += cx;
+ }
+ if ((anchors & ANCHOR_BOTTOM) && (!(anchors & ANCHOR_TOP)))
+ {
+ rChild.top += cy;
+ }
+ return rChild;
+}
+
+void AnchorMoveWindow(HWND window, const WINDOWPOS *parentPos, int anchors)
+{
+ RECT rParent;
+ RECT rChild;
+
+ if (parentPos->flags & SWP_NOSIZE)
+ {
+ return;
+ }
+ GetWindowRect(parentPos->hwnd, &rParent);
+ rChild = AnchorCalcPos(window, &rParent, parentPos, anchors);
+ MoveWindow(window, rChild.left, rChild.top, rChild.right - rChild.left, rChild.bottom - rChild.top, FALSE);
+}
+
+void AddAnchorWindowToDeferList(HDWP &hdWnds, HWND window, RECT *rParent, WINDOWPOS *wndPos, int anchors)
+{
+ RECT rChild = AnchorCalcPos(window, rParent, wndPos, anchors);
+ hdWnds = DeferWindowPos(hdWnds, window, HWND_NOTOPMOST, rChild.left, rChild.top, rChild.right - rChild.left, rChild.bottom - rChild.top, SWP_NOZORDER);
+}
+//************************************************************
+
+//Stucture passed to list sort function
+struct SortParams{
+ HWND hList;
+ int column;
+};
+
+static int lastColumn = -1; //last sort column
+
+int MatchesFilterCS(const TCHAR *filter, const PopupHistoryData *popupItem) //case sensitive
+{
+ if (_tcslen(filter) <= 0) { return 1; } //if no filter is set then the popup item matches the filter
+ int match = 0;
+
+ match = (_tcsstr(popupItem->messageT, filter)) ? 1 : match; //check message part
+
+ if (!match) //check title part of no match has been found
+ {
+ match = (_tcsstr(popupItem->titleT, filter)) ? 1 : match;
+ }
+
+ if (!match) //if no match has been found yet try to match the timestamp
+ {
+ TCHAR buffer[1024];
+ struct tm *myTime = localtime(&popupItem->timestamp);
+ _tcsftime(buffer, 1024, _T("%c"), myTime);
+ match = (_tcsstr(buffer, filter)) ? 1 : match;
+ }
+
+ return match;
+}
+
+__inline void ConvertCase(TCHAR *dest, const TCHAR *source, size_t size)
+{
+ _tcsncpy(dest, source, size);
+ _tcslwr(dest);
+}
+
+int MatchesFilterCI(const TCHAR *filterS, const PopupHistoryData *popupItem)
+{
+ if (_tcslen(filterS) <= 0) { return 1; } //if no filter is set then the popup item matches the filter
+ int match = 0;
+ const int BUFFER_SIZE = 1024;
+ TCHAR buffer[BUFFER_SIZE];
+ TCHAR filterI[BUFFER_SIZE];
+
+ ConvertCase(filterI, filterS, BUFFER_SIZE);
+
+ ConvertCase(buffer, popupItem->messageT, BUFFER_SIZE); //check message part
+ match = (_tcsstr(buffer, filterI)) ? 1 : match;
+
+ if (!match) // check title part of no match has been found
+ {
+ ConvertCase(buffer, popupItem->titleT, BUFFER_SIZE);
+ match = (_tcsstr(buffer, filterI)) ? 1 : match;
+ }
+
+ if (!match) //if no match has been found yet try to match the timestamp
+ {
+ struct tm *myTime = localtime(&popupItem->timestamp);
+ _tcsftime(buffer, 1024, _T("%c"), myTime);
+ match = (_tcsstr(buffer, filterI)) ? 1 : match;
+ }
+
+ return match;
+}
+
+int CALLBACK PopupsCompare(LPARAM lParam1, LPARAM lParam2, LPARAM myParam)
+{
+ SortParams params = *(SortParams *) myParam;
+ const int MAX_SIZE = 512;
+ TCHAR text1[MAX_SIZE];
+ TCHAR text2[MAX_SIZE];
+ int res;
+
+ ListView_GetItemText(params.hList, (int) lParam1, params.column, text1, MAX_SIZE);
+ ListView_GetItemText(params.hList, (int) lParam2, params.column, text2, MAX_SIZE);
+
+ res = _tcsicmp(text1, text2);
+
+ res = (params.column == lastColumn) ? -res : res; //do reverse search on second click on same column
+
+ return res;
+}
+
+
+
+int CalcCustomControlPos(IEVIEWWINDOW *ieWnd, HWND hMainWindow)
+{
+ RECT rect;
+ GetWindowRect(GetDlgItem(hMainWindow, IDC_LST_HISTORY), &rect);
+ ScreenToClient(hMainWindow, &rect);
+ //GetClientRect(hMainWindow, &rect);
+
+ ieWnd->x = rect.left + GAP_SIZE;
+ ieWnd->y = rect.top + GAP_SIZE;
+ ieWnd->cx = rect.right - rect.left - (2 * GAP_SIZE);
+ ieWnd->cy = rect.bottom - rect.top - (2 * GAP_SIZE);
+ return 0;
+}
+
+void MoveCustomControl(HWND hWnd, int renderer)
+{
+ switch (renderer)
+ {
+ case RENDER_HISTORYPP:
+ case RENDER_IEVIEW:
+ {
+ PopupHistoryWindowData *data = (PopupHistoryWindowData *) GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ if (data)
+ {
+ IEVIEWWINDOW ieWnd = {0};
+ ieWnd.cbSize = sizeof(ieWnd);
+ ieWnd.parent = hWnd;
+ ieWnd.hwnd = data->hIEView;
+ ieWnd.iType = IEW_SETPOS;
+ CalcCustomControlPos(&ieWnd, hWnd);
+
+ CallService((renderer == RENDER_HISTORYPP) ? MS_HPP_EG_WINDOW : MS_IEVIEW_WINDOW, 0, (LPARAM) &ieWnd);
+ }
+
+ break;
+ }
+ }
+}
+
+void LoadRenderer(HWND hWnd, int renderer)
+{
+ switch (renderer)
+ {
+ case RENDER_HISTORYPP:
+ case RENDER_IEVIEW:
+ {
+ IEVIEWWINDOW ieWnd = {0};
+
+ ieWnd.cbSize = sizeof(ieWnd);
+ ieWnd.iType = IEW_CREATE;
+ ieWnd.dwMode = IEWM_HISTORY;
+ ieWnd.dwFlags = 0;
+ ieWnd.parent = hWnd;
+ CalcCustomControlPos(&ieWnd, hWnd);
+
+ CallService((renderer == RENDER_HISTORYPP) ? MS_HPP_EG_WINDOW : MS_IEVIEW_WINDOW, 0, (LPARAM) &ieWnd); //create the IeView or H++ control.
+
+ PopupHistoryWindowData *data = (PopupHistoryWindowData *) mir_alloc(sizeof(PopupHistoryWindowData)); //create custom control data
+ data->hIEView = ieWnd.hwnd;
+ ShowWindow(data->hIEView, SW_SHOW);
+ SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); //set it as the window's user data
+ ShowWindow(GetDlgItem(hWnd, IDC_LST_HISTORY), SW_HIDE);
+ //SetWindowPos(GetDlgItem(hWnd, IDC_LST_HISTORY), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+
+ break;
+ }
+ }
+}
+
+void UnloadRenderer(HWND hWnd, int renderer)
+{
+ switch (renderer)
+ {
+ case RENDER_HISTORYPP:
+ case RENDER_IEVIEW:
+ {
+ PopupHistoryWindowData *data = (PopupHistoryWindowData *) GetWindowLongPtr(hWnd, GWLP_USERDATA);
+
+ if (data)
+ {
+ IEVIEWWINDOW ieWnd = {0};
+ ieWnd.cbSize = sizeof(ieWnd);
+ ieWnd.parent = hWnd;
+ ieWnd.hwnd = data->hIEView;
+ ieWnd.iType = IEW_DESTROY;
+ CallService((renderer == RENDER_HISTORYPP) ? MS_HPP_EG_WINDOW : MS_IEVIEW_WINDOW, 0, (LPARAM) &ieWnd);
+
+ mir_free(data);
+ }
+
+ break;
+ }
+ }
+}
+
+void DeleteOldEvents(HWND hWnd, int renderer)
+{
+ switch (renderer)
+ {
+ case RENDER_HISTORYPP:
+ case RENDER_IEVIEW:
+ {
+ PopupHistoryWindowData *data = (PopupHistoryWindowData *) GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ if (data)
+ {
+ IEVIEWEVENT ieEvent = {0};
+ ieEvent.cbSize = sizeof(IEVIEWEVENT);
+ ieEvent.hwnd = data->hIEView;
+ ieEvent.iType = IEE_CLEAR_LOG;
+
+ CallService((renderer == RENDER_HISTORYPP) ? MS_HPP_EG_EVENT : MS_IEVIEW_EVENT, 0, (LPARAM) &ieEvent);
+ }
+
+ break;
+ }
+
+ case RENDER_DEFAULT:
+ default:
+ {
+ ListView_DeleteAllItems(GetDlgItem(hWnd, IDC_LST_HISTORY));
+
+ break;
+ }
+
+ }
+}
+
+typedef int (*SIG_MATCHESFILTER)(const TCHAR *filter, const PopupHistoryData *popupItem);
+typedef void (*SIG_ADDEVENTS)(HWND hWnd, int renderer, TCHAR *filter, SIG_MATCHESFILTER MatchesFilter);
+
+IEVIEWEVENTDATA *CreateAndFillEventData(PopupHistoryData *popupItem)
+{
+ IEVIEWEVENTDATA *eventData = (IEVIEWEVENTDATA *) mir_calloc(sizeof(IEVIEWEVENTDATA));
+ if (eventData)
+ {
+ eventData->cbSize = sizeof(IEVIEWEVENTDATA);
+ eventData->iType = IEED_EVENT_MESSAGE;
+
+ eventData->dwFlags = IEEDF_UNICODE_NICK | IEEDF_UNICODE_TEXT | IEEDF_UNICODE_TEXT2;
+ eventData->pszNickW = popupItem->titleT;
+ eventData->pszTextW = popupItem->messageT;
+
+ eventData->time = (DWORD) popupItem->timestamp;
+ eventData->next = NULL;
+ }
+
+ return eventData;
+}
+
+void AddEventsCustomControl(HWND hWnd, int renderer, TCHAR *filter, SIG_MATCHESFILTER MatchesFilter)
+{
+ PopupHistoryWindowData *pwData = (PopupHistoryWindowData *) GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ if (pwData)
+ {
+ IEVIEWEVENT ieEvent = {0};
+ ieEvent.cbSize = sizeof(IEVIEWEVENT);
+ ieEvent.hwnd = pwData->hIEView;
+ ieEvent.codepage = CP_ACP;
+ ieEvent.iType = IEE_LOG_MEM_EVENTS;
+ ieEvent.hContact = NULL;//(HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); IEVIEW needs a contact handle !!
+
+ IEVIEWEVENTDATA *eventData = NULL;
+ IEVIEWEVENTDATA *cED = NULL;
+ IEVIEWEVENTDATA *prevED = NULL;
+
+ int i;
+ int count = 0;
+ int size = lstPopupHistory.Count();
+ PopupHistoryData *popupItem;
+
+ for (i = 0; i < size; i++)
+ {
+ popupItem = lstPopupHistory.Get(i);
+ if (MatchesFilter(filter, popupItem))
+ {
+ cED = CreateAndFillEventData(popupItem);
+ if (cED)
+ {
+ count++;
+ if (!eventData)
+ {
+ eventData = cED;
+ }
+ else{
+ prevED->next = cED;
+ }
+
+ prevED = cED;
+ }
+ }
+ }
+ ieEvent.count = count;
+ ieEvent.eventData = eventData;
+
+ CallService((renderer == RENDER_HISTORYPP) ? MS_HPP_EG_EVENT : MS_IEVIEW_EVENT, 0, (LPARAM) &ieEvent);
+
+ while (eventData)
+ {
+ cED = eventData;
+ eventData = eventData->next;
+ mir_free(cED);
+ }
+ }
+}
+
+void AddEventsDefault(HWND hWnd, int renderer, TCHAR *filter, SIG_MATCHESFILTER MatchesFilter)
+{
+ HWND hHistoryList = GetDlgItem(hWnd, IDC_LST_HISTORY);
+ TCHAR buffer[1024];
+ struct tm *myTime;
+
+ LVITEM item = {0};
+ item.mask = LVIF_TEXT;
+
+ int i, lIndex;
+ lIndex = 0;
+ PopupHistoryData *popupItem;
+ for (i = 0; i < lstPopupHistory.Count(); i++)
+ {
+ item.iItem = lIndex;
+ popupItem = lstPopupHistory.Get(i);
+ if (MatchesFilter(filter, popupItem))
+ {
+ item.pszText = popupItem->titleT;
+ ListView_InsertItem(hHistoryList, &item);
+ ListView_SetItemText(hHistoryList, lIndex, 1, popupItem->messageT);
+ myTime = localtime(&popupItem->timestamp);
+ _tcsftime(buffer, 1024, _T("%c"), myTime);
+ ListView_SetItemText(hHistoryList, lIndex++, 2, buffer);
+ }
+ }
+}
+
+void RefreshPopupHistory(HWND hWnd, int renderer)
+{
+ if (!hWnd) { return; }
+ const int MAX_FILTER_SIZE = 1024;
+ SIG_MATCHESFILTER MatchesFilter = (IsDlgButtonChecked(hWnd, IDC_HISTORY_FILTER_CASESENSITIVE)) ? MatchesFilterCS : MatchesFilterCI; //case sensitive compare or not ?
+
+ SIG_ADDEVENTS AddEvents = (renderer == RENDER_DEFAULT) ? AddEventsDefault : AddEventsCustomControl;
+
+ TCHAR filter[MAX_FILTER_SIZE];
+ DeleteOldEvents(hWnd, renderer); //delete events
+
+ GetWindowText(GetDlgItem(hWnd, IDC_HISTORY_FILTER), filter, MAX_FILTER_SIZE); //get filter text
+
+ AddEvents(hWnd, renderer, filter, MatchesFilter);
+
+ if (renderer == RENDER_DEFAULT)
+ {
+ HWND hHistoryList = GetDlgItem(hWnd, IDC_LST_HISTORY);
+ SortParams params = {0};
+ params.hList = hHistoryList;
+ params.column = lastColumn;
+
+ ListView_SortItemsEx(hHistoryList, PopupsCompare, &params);
+ }
+}
+
+void CopyPopupDataToClipboard(HWND hList, int selection)
+{
+ if (!selection)
+ {
+ return;
+ }
+
+ if (!GetOpenClipboardWindow())
+ {
+ if (OpenClipboard(hList))
+ {
+ TCHAR buffer[2048];
+ buffer[0] = _T('\0');
+ TCHAR *clipboard;
+ int i;
+ int found = 0;
+ int count = ListView_GetItemCount(hList);
+ int textType;
+
+ textType = CF_UNICODETEXT;
+
+
+ for (i = 0; i < count; i++)
+ {
+ if (ListView_GetItemState(hList, i, LVIS_SELECTED))
+ {
+ ListView_GetItemText(hList, i, selection - 100, buffer, 2048);
+ found = 1;
+ break;
+ }
+ }
+ if (found)
+ {
+ EmptyClipboard();
+ int len = (int)_tcslen(buffer);
+
+ HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, (len + 2) * sizeof(TCHAR));
+ clipboard = (TCHAR *) GlobalLock(hData);
+ _tcsncpy(clipboard, buffer, len);
+ clipboard[len] = _T('\0');
+ GlobalUnlock(hData);
+ if (!SetClipboardData(textType, hData))
+ {
+ PUShowMessage("Could not set clipboard data", SM_WARNING);
+ }
+ }
+ CloseClipboard();
+ }
+ else{
+ PUShowMessage("Could not open clipboard", SM_WARNING);
+ }
+ }
+ else{
+ PUShowMessage("The clipboard is not available", SM_WARNING);
+ }
+}
+
+//subclass proc for the list view
+BOOL CALLBACK PopupsListSubclassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_CONTEXTMENU:
+ {
+ int x = LOWORD(lParam);
+ int y = HIWORD(lParam);
+ int selection;
+
+ HMENU hMenu = CreatePopupMenu();
+ AppendMenu(hMenu, MF_STRING, POPUPMENU_TITLE, TranslateT("Copy title to clipboard"));
+ AppendMenu(hMenu, MF_STRING, POPUPMENU_MESSAGE, TranslateT("Copy message to clipboard"));
+ AppendMenu(hMenu, MF_STRING, POPUPMENU_TIMESTAMP, TranslateT("Copy timestamp to clipboard"));
+ selection = TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, x, y, 0, hWnd, NULL);
+ DestroyMenu(hMenu);
+ if (selection)
+ {
+ CopyPopupDataToClipboard(hWnd, selection);
+ }
+
+ break;
+ }
+
+ case WM_KEYUP:
+ {
+ switch (wParam)
+ {
+ case 'C':
+ {
+ if (GetKeyState(VK_CONTROL))
+ {
+ CopyPopupDataToClipboard(hWnd, POPUPMENU_MESSAGE);
+ }
+
+ break;
+ }
+
+ case VK_ESCAPE:
+ {
+ SendMessage(GetParent(hWnd), WM_CLOSE, 0, 0);
+
+ break;
+ }
+
+ }
+
+ break;
+ }
+
+ case WM_SYSKEYDOWN:
+ {
+ if (wParam == 'X')
+ {
+ SendMessage(GetParent(hWnd), WM_CLOSE, 0, 0);
+ }
+
+ break;
+ }
+ }
+
+ return CallWindowProc(oldPopupsListProc, hWnd, msg, wParam, lParam);
+}
+
+//load the columns
+void LoadHistoryColumns(HWND hHistoryList)
+{
+ LVCOLUMN col;
+ col.mask = LVCF_TEXT | LVCF_WIDTH;
+ int i;
+
+ for (i = 0; i < cHistoryColumns; i++)
+ {
+ col.pszText = TranslateTS(szHistoryColumns[i]);
+ col.cx = cxHistoryColumns[i];
+ ListView_InsertColumn(hHistoryList, i, &col);
+ }
+}
+
+//this is the history list window handler
+INT_PTR CALLBACK DlgProcHistLst(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int bInitializing;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ bInitializing = 1;
+ int renderer = lstPopupHistory.GetRenderer();
+
+ SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM) hiPopupHistory);
+
+ LoadRenderer(hWnd, renderer);
+
+ TranslateDialogDefault(hWnd);
+ HWND hHistoryList = GetDlgItem(hWnd, IDC_LST_HISTORY);
+
+ ListView_SetExtendedListViewStyleEx(hHistoryList, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
+
+ oldPopupsListProc = (WNDPROC) SetWindowLongPtr(hHistoryList, GWLP_WNDPROC, (LONG_PTR) PopupsListSubclassProc);
+
+ LoadHistoryColumns(hHistoryList);
+
+ RefreshPopupHistory(hWnd, renderer);
+
+ bInitializing = 0;
+
+ return TRUE;
+ }
+
+ case WM_DESTROY:
+ {
+ UnloadRenderer(hWnd, lstPopupHistory.GetRenderer());
+ hHistoryWindow = NULL;
+
+ break;
+ }
+
+ case WM_CLOSE:
+ {
+ //Utils_SaveWindowPosition(hWnd, 0, MODULE, "history_dlg");
+ DestroyWindow(hWnd);
+
+ break;
+ }
+
+ case WM_WINDOWPOSCHANGING:
+ {
+ WINDOWPOS *wndPos = (WINDOWPOS *) lParam;
+
+ if (wndPos->cx < MIN_HISTORY_WIDTH)
+ {
+ wndPos->cx = MIN_HISTORY_WIDTH;
+ }
+ if (wndPos->cy < MIN_HISTORY_HEIGHT)
+ {
+ wndPos->cy = MIN_HISTORY_HEIGHT;
+ }
+
+ RECT rParent;
+ GetWindowRect(hWnd, &rParent);
+ HDWP hdWnds = BeginDeferWindowPos(4);
+
+ AddAnchorWindowToDeferList(hdWnds, GetDlgItem(hWnd, IDC_CLOSE), &rParent, wndPos, ANCHOR_RIGHT | ANCHOR_BOTTOM);
+ AddAnchorWindowToDeferList(hdWnds, GetDlgItem(hWnd, IDC_HISTORY_FILTER), &rParent, wndPos, ANCHOR_LEFT | ANCHOR_BOTTOM);
+ AddAnchorWindowToDeferList(hdWnds, GetDlgItem(hWnd, IDC_HISTORY_FILTER_CASESENSITIVE), &rParent, wndPos, ANCHOR_LEFT | ANCHOR_RIGHT | ANCHOR_BOTTOM);
+ AddAnchorWindowToDeferList(hdWnds, GetDlgItem(hWnd, IDC_LST_HISTORY), &rParent, wndPos, ANCHOR_ALL);
+
+ EndDeferWindowPos(hdWnds);
+ MoveCustomControl(hWnd, lstPopupHistory.GetRenderer()); //move the custom control too, if any
+ break;
+ }
+
+
+ case WM_COMMAND:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_CLOSE:
+ {
+ SendMessage(hWnd, WM_CLOSE, 0, 0);
+
+ break;
+ }
+
+ case IDC_HISTORY_FILTER_CASESENSITIVE:
+ {
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ RefreshPopupHistory(hWnd, lstPopupHistory.GetRenderer());
+ }
+ }
+
+ case IDC_HISTORY_FILTER:
+ {
+ if (HIWORD(wParam) == EN_CHANGE)
+ {
+ if (!bInitializing)
+ {
+ RefreshPopupHistory(hWnd, lstPopupHistory.GetRenderer());
+ }
+ }
+
+ break;
+ }
+
+ }
+
+ break;
+ }
+
+ case WM_NOTIFY:
+ {
+ switch(((LPNMHDR)lParam)->idFrom)
+ {
+ case IDC_LST_HISTORY:
+ {
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case LVN_COLUMNCLICK:
+ {
+ LPNMLISTVIEW lv = (LPNMLISTVIEW) lParam;
+ int column = lv->iSubItem;
+ SortParams params = {0};
+ params.hList = GetDlgItem(hWnd, IDC_LST_HISTORY);
+ params.column = column;
+
+ ListView_SortItemsEx(params.hList, PopupsCompare, (LPARAM) &params);
+ lastColumn = (params.column == lastColumn) ? -1 : params.column;
+
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+
+ return 0;
+}