/* Miranda IM Country Flags Plugin Copyright (C) 2006-1007 H. Herkenrath This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (Flags-License.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "stdafx.h" /************************* Buffered Functions *********************/ struct BufferedCallData { DWORD startTick; UINT uElapse; BUFFEREDPROC pfnBuffProc; LPARAM lParam; #ifdef _DEBUG const char *pszProcName; #endif }; static UINT idBufferedTimer; static struct BufferedCallData *callList; static int nCallListCount; // always gets called in main message loop static void CALLBACK BufferedProcTimer(HWND hwnd, UINT, UINT_PTR idTimer, DWORD currentTick) { BufferedCallData *buf; UINT uElapsed, uElapseNext = USER_TIMER_MAXIMUM; BUFFEREDPROC pfnBuffProc; LPARAM lParam; #ifdef _DEBUG char szDbgLine[256]; const char *pszProcName; #endif for (int i = 0; i < nCallListCount; ++i) { /* find elapsed procs */ uElapsed = currentTick - callList[i].startTick; /* wraparound works */ if ((uElapsed + USER_TIMER_MINIMUM) >= callList[i].uElapse) { /* call elapsed proc */ pfnBuffProc = callList[i].pfnBuffProc; lParam = callList[i].lParam; #ifdef _DEBUG pszProcName = callList[i].pszProcName; #endif /* resize storage array */ if ((i + 1) < nCallListCount) memmove(&callList[i], &callList[i + 1], ((nCallListCount - i - 1)*sizeof(struct BufferedCallData))); --nCallListCount; --i; /* reiterate current */ if (nCallListCount) { buf = (struct BufferedCallData*)mir_realloc(callList, nCallListCount*sizeof(struct BufferedCallData)); if (buf != nullptr) callList = buf; } else { mir_free(callList); callList = nullptr; } #ifdef _DEBUG mir_snprintf(szDbgLine, "buffered call: %s(0x%X)\n", pszProcName, lParam); /* all ascii */ OutputDebugStringA(szDbgLine); #endif CallFunctionAsync((void (CALLBACK *)(void*))pfnBuffProc, (void*)lParam); /* compatible */ } /* find next timer delay */ else if ((callList[i].uElapse - uElapsed) < uElapseNext) uElapseNext = callList[i].uElapse - uElapsed; } /* set next timer */ if (nCallListCount) { #ifdef _DEBUG mir_snprintf(szDbgLine, "next buffered timeout: %ums\n", uElapseNext); /* all ascii */ OutputDebugStringA(szDbgLine); #endif idBufferedTimer = SetTimer(hwnd, idBufferedTimer, uElapseNext, BufferedProcTimer); /* will be reset */ } else { KillTimer(hwnd, idTimer); idBufferedTimer = 0; #ifdef _DEBUG OutputDebugStringA("empty buffered queue\n"); #endif } } // assumes to be called in context of main thread #ifdef _DEBUG void _CallFunctionBuffered(BUFFEREDPROC pfnBuffProc, const char *pszProcName, LPARAM lParam, BOOL fAccumulateSameParam, UINT uElapse) #else void _CallFunctionBuffered(BUFFEREDPROC pfnBuffProc, LPARAM lParam, BOOL fAccumulateSameParam, UINT uElapse) #endif { struct BufferedCallData *data = nullptr; int i; /* find existing */ for (i = 0; i < nCallListCount; ++i) if (callList[i].pfnBuffProc == pfnBuffProc) if (!fAccumulateSameParam || callList[i].lParam == lParam) { data = &callList[i]; break; } /* append new */ if (data == nullptr) { /* resize storage array */ data = (struct BufferedCallData*)mir_realloc(callList, (nCallListCount + 1)*sizeof(struct BufferedCallData)); if (data == nullptr) return; callList = data; data = &callList[nCallListCount]; ++nCallListCount; } /* set delay */ data->startTick = GetTickCount(); data->uElapse = uElapse; data->lParam = lParam; data->pfnBuffProc = pfnBuffProc; #ifdef _DEBUG { char szDbgLine[256]; data->pszProcName = pszProcName; mir_snprintf(szDbgLine, "buffered queue: %s(0x%X)\n", pszProcName, lParam); /* all ascii */ OutputDebugStringA(szDbgLine); if (!idBufferedTimer) { mir_snprintf(szDbgLine, "next buffered timeout: %ums\n", uElapse); /* all ascii */ OutputDebugStringA(szDbgLine); } } #endif /* set next timer */ if (idBufferedTimer) uElapse = USER_TIMER_MINIMUM; /* will get recalculated */ idBufferedTimer = SetTimer(nullptr, idBufferedTimer, uElapse, BufferedProcTimer); } // assumes to be called in context of main thread void PrepareBufferedFunctions(void) { idBufferedTimer = 0; nCallListCount = 0; callList = nullptr; } // assumes to be called in context of main thread void KillBufferedFunctions(void) { if (idBufferedTimer) KillTimer(nullptr, idBufferedTimer); nCallListCount = 0; mir_free(callList); /* does NULL check */ }