From 10a3bfa53858f75fa64833ce5d860a14a756c38a Mon Sep 17 00:00:00 2001 From: sje Date: Wed, 1 Nov 2006 14:37:22 +0000 Subject: git-svn-id: https://server.scottellis.com.au/svn/mim_plugs@7 4f64403b-2f21-0410-a795-97e2b3489a10 --- message_notify/messagenotify.cpp | 372 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 372 insertions(+) create mode 100644 message_notify/messagenotify.cpp (limited to 'message_notify/messagenotify.cpp') diff --git a/message_notify/messagenotify.cpp b/message_notify/messagenotify.cpp new file mode 100644 index 0000000..69595b2 --- /dev/null +++ b/message_notify/messagenotify.cpp @@ -0,0 +1,372 @@ +//////////////////////////////////// +/// This Miranda plugin (http://www.miranda-im.org) is released under the General Public Licence, +/// available at http://www.gnu.org/copyleft/gpl.html +/// Copyright Scott Ellis 2005 (mail@scottellis.com.au .. www.scottellis.com.au) +//////////////////////////////////// + +#include "common.h" +#include "options.h" +#include "popups.h" +#include + +HINSTANCE hInst; +PLUGINLINK *pluginLink; + +HANDLE mainThread; + +bool metacontacts_installed; +bool unicode_system; + +int code_page = CP_ACP; + +HANDLE popupWindowList; + +DWORD focusTimerId = 0; + +PLUGININFO pluginInfo={ + sizeof(PLUGININFO), + "Message Notify", + PLUGIN_MAKE_VERSION(0,1,1,1), + "Show a popup when a message is received", + "Scott Ellis", + "mail@scottellis.com.au", + "© 2005 Scott Ellis", + "http://www.scottellis.com.au/", + 0, //not transient + 0 //doesn't replace anything built-in +}; + + +extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) +{ + hInst=hinstDLL; + DisableThreadLibraryCalls(hInst); + return TRUE; +} + +extern "C" __declspec(dllexport) PLUGININFO* MirandaPluginInfo(DWORD mirandaVersion) +{ + return &pluginInfo; +} + +HANDLE hWindowEvent, hEventDbEventAdded, hIdle; +BOOL bIsIdle = FALSE; + +bool window_focussed(HWND hwnd, HANDLE hContact) { + HWND parent; + while((parent = GetParent(hwnd)) != 0) hwnd = parent; // ensure we have the top level window (need parent window for scriver & tabsrmm) + + // consider minimized window not-focussed + WINDOWPLACEMENT wp = {0}; + wp.length = sizeof(wp); + GetWindowPlacement(hwnd, &wp); + if(hwnd == GetForegroundWindow() && !(wp.showCmd & SW_SHOWMINIMIZED)) { + + // check message API for focus too + if(options.consider_tabs) { + MessageWindowInputData mwid = {0}; + MessageWindowData mwd = {0}; + + mwid.cbSize = sizeof(mwid); + mwid.hContact = hContact; + mwid.uFlags = MSG_WINDOW_UFLAG_MSG_BOTH; + + mwd.cbSize = sizeof(mwd); + + if(!CallService(MS_MSG_GETWINDOWDATA, (WPARAM)&mwid, (LPARAM)&mwd)) { + if((mwd.uState & MSG_WINDOW_STATE_VISIBLE) != 0) { + return true; + } + } else + return true; + + } else + return true; + } + + return false; +} + +void __stdcall FocusTimerProc(struct HWND__ *,unsigned int,unsigned int,unsigned long) { + if(options.notify_when != NOTIFY_NFORE) return; + + HANDLE hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact) { + HWND hwnd; + if((hwnd = (HWND)DBGetContactSettingDword(hContact, MODULE, "WindowHandle", 0)) != 0) { + if(!EmptyList(hContact)) { + if(window_focussed(hwnd, hContact)) + PostMessageWindowList(WMU_CLOSEPOPUP, (WPARAM)hContact, 0); // close popups + } + } + hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0); + } +} + +void StartFocusTimer() { + if(!focusTimerId) + focusTimerId = SetTimer(0, 0, 500, FocusTimerProc); +} + +void StopFocusTimer() { + if(focusTimerId) { + KillTimer(0, focusTimerId); + focusTimerId = 0; + } +} + + + +//#define CONTROL_GLOBAL_STATUS + +#ifdef CONTROL_GLOBAL_STATUS +WORD saved_status; +#endif + +int OnIdleChanged(WPARAM wParam, LPARAM lParam) { +#ifdef CONTROL_GLOBAL_STATUS + int st; +#endif + + bIsIdle = (lParam & IDF_ISIDLE); + +#ifdef CONTROL_GLOBAL_STATUS + st = CallService(MS_CLIST_GETSTATUSMODE, 0, 0); + if(bIsIdle && st != ID_STATUS_OFFLINE) { + saved_status = st; + CallService(MS_CLIST_SETSTATUSMODE, (WPARAM)ID_STATUS_AWAY, 0); + } else if(!bIsIdle && saved_status != ID_STATUS_OFFLINE) { + CallService(MS_CLIST_SETSTATUSMODE, (WPARAM)saved_status, 0); + } +#endif + + return 0; +} + +typedef struct { + HANDLE hContact; + BYTE *blob; + int blobsize; +} CheckWindowData; + +unsigned int __stdcall sttCheckWindowProc( VOID *dwParam ) { + CheckWindowData *cd = (CheckWindowData *)dwParam; + + Sleep(500); // wait for message window to open from event, if it's going to + + HWND hwnd = (HWND)DBGetContactSettingDword(cd->hContact, MODULE, "WindowHandle", 0); + bool window_open = (hwnd != 0); + bool window_has_focus = window_open && window_focussed(hwnd, cd->hContact); + + if(options.notify_when == NOTIFY_ALWAYS + || (options.notify_when == NOTIFY_NFORE && !window_has_focus) + || (options.notify_when == NOTIFY_CLOSED && !window_open)) + { + if(IsUnicodePopupsEnabled()) { + // get contact display name from clist + wchar_t *swzContactDisplayName = 0; + + if(unicode_system) + swzContactDisplayName = (wchar_t *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)cd->hContact, GCDNF_UNICODE); + else { + char *szCDN = (char *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)cd->hContact, 0); + if(szCDN && szCDN[0]) { + int size = MultiByteToWideChar(code_page, 0, (char *) szCDN, -1, 0, 0); + swzContactDisplayName = (wchar_t *) malloc(sizeof(wchar_t) * size); + MultiByteToWideChar(code_page, 0, (char *) szCDN, -1, swzContactDisplayName, size); + } else { + swzContactDisplayName = (wchar_t *) malloc(sizeof(wchar_t) * (wcslen(TranslateT("(Unknown)") + 1))); + wcscpy(swzContactDisplayName, TranslateT("(Unknown)")); + } + } + + wchar_t *msg; + int msglen = strlen((char *)cd->blob) + 1; + + // does blob contain unicode message? + if(msglen != cd->blobsize && wcslen((wchar_t *)(&cd->blob[msglen]))) { + // yes + msg = (wchar_t *)(&cd->blob[msglen]); + ShowPopupW(cd->hContact, swzContactDisplayName, msg); + } else if(cd->blobsize) { + // no, convert to unciode + int size = MultiByteToWideChar(code_page, 0, (char *) cd->blob, -1, 0, 0); + msg = (wchar_t *) malloc(sizeof(wchar_t) * size); + MultiByteToWideChar(code_page, 0, (char *) cd->blob, -1, msg, size); + ShowPopupW(cd->hContact, swzContactDisplayName, msg); + free(msg); + } + if(!unicode_system) free(swzContactDisplayName); + } else { + char *szCDN = (char *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)cd->hContact, 0); + if(szCDN && szCDN[0]) { + char msg[MAX_SECONDLINE]; + strncpy(msg, (char *)cd->blob, MAX_SECONDLINE - 1); + msg[MAX_SECONDLINE - 1] = 0; + ShowPopup(cd->hContact, szCDN, (char *)msg); + } + } + } + + delete[] cd->blob; + delete cd; + + return 0; +} + +int OnDatabaseEventPreAdd(WPARAM wParam, LPARAM lParam) { + DBEVENTINFO *dbei = (DBEVENTINFO *)lParam; + + // safety checks + + if ((dbei == 0) || (wParam == 0) || (dbei->flags & DBEF_SENT) || (dbei->eventType != EVENTTYPE_MESSAGE) || (dbei->flags & DBEF_READ)) { + return 0; + } + + int status = CallService(MS_CLIST_GETSTATUSMODE, 0, 0); + if(status >= ID_STATUS_ONLINE && status <= ID_STATUS_OUTTOLUNCH && options.disable_status[status - ID_STATUS_ONLINE]) + return 0; + + // messages from this contact ignored + if(CallService(MS_IGNORE_ISIGNORED, wParam, (LPARAM)IGNOREEVENT_MESSAGE)) + return 0; + + // if contact 'not on list', use default ignore setting + if(DBGetContactSettingByte((HANDLE)wParam, "CList", "NotOnList", 0) && CallService(MS_IGNORE_ISIGNORED, 0, (LPARAM)IGNOREEVENT_MESSAGE)) + return 0; + + if(dbei->cbBlob == 0 || dbei->pBlob == 0) + return 0; // just to be safe + + + // copy blob data + CheckWindowData *cd = new CheckWindowData; + cd->hContact = (HANDLE)wParam; + cd->blobsize = dbei->cbBlob; + cd->blob = new BYTE[cd->blobsize]; + memcpy(cd->blob, dbei->pBlob, cd->blobsize); + + // spawn a thread to deal with the copied data + CloseHandle((HANDLE)_beginthreadex(0, 0, sttCheckWindowProc, (VOID *)cd, 0, 0)); + return 0; +} + +int OnWindowEvent(WPARAM wParam, LPARAM lParam) { + MessageWindowEventData *mwed = (MessageWindowEventData *)lParam; + + switch(mwed->uType) { + case MSG_WINDOW_EVT_OPENING: + case MSG_WINDOW_EVT_OPEN: + DBWriteContactSettingDword(mwed->hContact, MODULE, "WindowHandle", (DWORD)mwed->hwndWindow); + if(options.notify_when == NOTIFY_CLOSED) + PostMessageWindowList(WMU_CLOSEPOPUP, (WPARAM)mwed->hContact, 0); + break; + case MSG_WINDOW_EVT_CLOSING: + case MSG_WINDOW_EVT_CLOSE: + DBWriteContactSettingDword(mwed->hContact, MODULE, "WindowHandle", 0); + break; + default: + //ShowWarning("Window custom"); + break; + } + + return 0; +} + +int OnModulesLoaded(WPARAM wParam, LPARAM lParam) { + InitUtils(); // depends on popup module being loaded already + + if(ServiceExists(MS_UPDATE_REGISTER)) { + // register with updater + Update update = {0}; + char szVersion[16]; + + update.cbSize = sizeof(Update); + + update.szComponentName = pluginInfo.shortName; + update.pbVersion = (BYTE *)CreateVersionString(pluginInfo.version, szVersion); + update.cpbVersion = strlen((char *)update.pbVersion); + + update.szUpdateURL = UPDATER_AUTOREGISTER; + + update.szBetaUpdateURL = "http://www.scottellis.com.au/miranda_plugins/messagenotify.zip"; + update.szBetaVersionURL = "http://www.scottellis.com.au/miranda_plugins/ver_messagenotify.html"; + update.pbBetaVersionPrefix = (BYTE *)"Message Notify version "; + + update.cpbBetaVersionPrefix = strlen((char *)update.pbBetaVersionPrefix); + + CallService(MS_UPDATE_REGISTER, 0, (WPARAM)&update); + } + + metacontacts_installed = (ServiceExists(MS_MC_GETMETACONTACT) != 0); + + hIdle = HookEvent(ME_IDLE_CHANGED, OnIdleChanged); + hWindowEvent = HookEvent(ME_MSG_WINDOWEVENT, OnWindowEvent); + + if(options.notify_when == NOTIFY_NFORE) + StartFocusTimer(); + + return 0; +} + +int OnPreShutdown(WPARAM wParam, LPARAM lParam) { + StopFocusTimer(); + return 0; +} + +extern "C" int __declspec(dllexport) Load(PLUGINLINK *link) +{ + pluginLink = link; + DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &mainThread, THREAD_SET_CONTEXT, FALSE, 0 ); + + char szVer[128]; + unicode_system = (CallService(MS_SYSTEM_GETVERSIONTEXT, (WPARAM)sizeof(szVer), (LPARAM)szVer) == 0 && strstr(szVer, "Unicode")); + + INITCOMMONCONTROLSEX icex; + + // Ensure that the common control DLL is loaded (for listview) + icex.dwSize = sizeof(INITCOMMONCONTROLSEX); + icex.dwICC = ICC_LISTVIEW_CLASSES; + InitCommonControlsEx(&icex); + + if(ServiceExists(MS_DB_SETSETTINGRESIDENT)) { // 0.6+ + CallService(MS_DB_SETSETTINGRESIDENT, TRUE, (LPARAM)(MODULE "/WindowHandle")); + } + + HANDLE hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact) { + if(DBGetContactSettingDword(hContact, MODULE, "WindowHandle", 0) != 0) + DBWriteContactSettingDword(hContact, MODULE, "WindowHandle", 0); + + hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0); + } + + InitWindowList(); + + LoadOptions(); + + if(ServiceExists(MS_LANGPACK_GETCODEPAGE)) + code_page = CallService(MS_LANGPACK_GETCODEPAGE, 0, 0); + + HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded); + HookEvent(ME_SYSTEM_PRESHUTDOWN, OnPreShutdown); + HookEvent(ME_OPT_INITIALISE, OptInit); + + popupWindowList = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0); + + hEventDbEventAdded = HookEvent(ME_DB_EVENT_FILTER_ADD, OnDatabaseEventPreAdd); + + return 0; +} + +extern "C" int __declspec(dllexport) Unload(void) +{ + UnhookEvent(hIdle); + UnhookEvent(hWindowEvent); + UnhookEvent(hEventDbEventAdded); + + DeinitUtils(); + DeinitWindowList(); + + return 0; +} -- cgit v1.2.3