From 144d05b638162094aabb5153483439589e103ed4 Mon Sep 17 00:00:00 2001 From: kreol13 Date: Thu, 21 Apr 2011 12:56:41 +0000 Subject: initial commit git-svn-id: http://miranda-plugins.googlecode.com/svn/trunk@3 e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb --- Flags/svc_flags.cpp | 765 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 765 insertions(+) create mode 100644 Flags/svc_flags.cpp (limited to 'Flags/svc_flags.cpp') diff --git a/Flags/svc_flags.cpp b/Flags/svc_flags.cpp new file mode 100644 index 0000000..bc3619f --- /dev/null +++ b/Flags/svc_flags.cpp @@ -0,0 +1,765 @@ +/* +UserinfoEx plugin for Miranda IM + +Copyright: +ฉ 2006-2010 DeathAxe, Yasnovidyashii, Merlin, K. Romanov, Kreol + +part of this code based on: +Miranda IM Country Flags Plugin Copyright ฉ2006-2007 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; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +=============================================================================== + +File name : $HeadURL: https://userinfoex.googlecode.com/svn/trunk/Flags/svc_flags.cpp $ +Revision : $Revision: 187 $ +Last change on : $Date: 2010-09-08 16:05:54 +0400 (ะกั€, 08 ัะตะฝ 2010) $ +Last change by : $Author: ing.u.horn $ + +=============================================================================== +*/ + +#include "..\commonheaders.h" +#include "svc_flags.h" +#include "svc_flagsicons.h" +#include "svc_countrylistext.h" + +#define M_ENABLE_SUBCTLS (WM_APP+1) + +FLAGSOPTIONS gFlagsOpts; + +/* Misc */ +int nCountriesCount; +struct CountryListEntry *countries; +static HANDLE *phExtraImageList = NULL; //return value(s) from MS_CLIST_EXTRA_ADD_ICON +static HANDLE hExtraIconSvc = INVALID_HANDLE_VALUE; +/* hook */ +static HANDLE hRebuildIconsHook = NULL; +static HANDLE hApplyIconHook = NULL; +static HANDLE hMsgWndEventHook = NULL; +static HANDLE hIconsChangedHook = NULL; +static HANDLE hSettingChangedHook = NULL; + +static HANDLE hExtraIconSvcHook = NULL; +static HANDLE hOptInitHook = NULL; + +static int OnContactSettingChanged(WPARAM wParam,LPARAM lParam); + +/*********************************************************************************************************** + * Buffered functions + ***********************************************************************************************************/ + +struct BufferedCallData { + DWORD startTick; + UINT uElapse; + BUFFEREDPROC pfnBuffProc; + LPARAM lParam; + #ifdef _DEBUG + const char *pszProcName; + #endif +}; + +static UINT_PTR idBufferedTimer; +static struct BufferedCallData *callList; +static int nCallListCount; + +// always gets called in main message loop +static void CALLBACK BufferedProcTimer(HWND hwnd, UINT msg, UINT idTimer, DWORD currentTick) { + int i; + struct BufferedCallData *buf; + UINT uElapsed, uElapseNext = USER_TIMER_MAXIMUM; + BUFFEREDPROC pfnBuffProc; + LPARAM lParam; + #ifdef _DEBUG + char szDbgLine[256]; + const char *pszProcName; + #endif + UNREFERENCED_PARAMETER(msg); + + for(i=0;i=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)startTick=GetTickCount(); + data->uElapse=uElapse; + data->lParam=lParam; + data->pfnBuffProc=pfnBuffProc; + #ifdef _DEBUG + { char szDbgLine[256]; + data->pszProcName=pszProcName; + mir_snprintf(szDbgLine,sizeof(szDbgLine),"buffered queue: %s(0x%X)\n",pszProcName,lParam); /* all ascii */ + OutputDebugStringA(szDbgLine); + if(!idBufferedTimer) { + mir_snprintf(szDbgLine,sizeof(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(NULL,idBufferedTimer,uElapse,(TIMERPROC)BufferedProcTimer); +} + +// assumes to be called in context of main thread +void PrepareBufferedFunctions() +{ + idBufferedTimer=0; + nCallListCount=0; + callList=NULL; +} + +// assumes to be called in context of main thread +void KillBufferedFunctions() +{ + if(idBufferedTimer) KillTimer(NULL,idBufferedTimer); + nCallListCount=0; + mir_free(callList); /* does NULL check */ +} + +/*********************************************************************************************************** + * service functions + ***********************************************************************************************************/ + +static INT_PTR ServiceDetectContactOriginCountry(WPARAM wParam,LPARAM lParam) +{ + WORD countryNumber; + char *pszProto = + pszProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,wParam,0); + /* UserinfoEx */ + if (countryNumber = (int)DB::Setting::GetWord((HANDLE)wParam,USERINFO,SET_CONTACT_ORIGIN_COUNTRY,0)) + return (INT_PTR)countryNumber; + else if (countryNumber = (int)DB::Setting::GetWord((HANDLE)wParam,USERINFO,SET_CONTACT_COUNTRY,0)) + return (INT_PTR)countryNumber; + else if (countryNumber = (int)DB::Setting::GetWord((HANDLE)wParam,USERINFO,SET_CONTACT_COMPANY_COUNTRY,0)) + return (INT_PTR)countryNumber; + /* fallback proto settings */ + else if (countryNumber = (int)DB::Setting::GetWord((HANDLE)wParam,pszProto,"Country",0)) + return (INT_PTR)countryNumber; + else if (countryNumber = (int)DB::Setting::GetWord((HANDLE)wParam,pszProto,"CompanyCountry",0)) + return (INT_PTR)countryNumber; + /* fallback ip detect + else if(countryNumber==0xFFFF && DBGetContactSettingByte(NULL,"Flags","UseIpToCountry",SETTING_USEIPTOCOUNTRY_DEFAULT)){ + countryNumber=ServiceIpToCountry(DBGetContactSettingDword((HANDLE)wParam,pszProto,"RealIP",0),0); + }*/ + + return (INT_PTR)0xFFFF; +} + +/*********************************************************************************************************** + * Clist Extra Image functions + ***********************************************************************************************************/ + +static void CALLBACK SetExtraImage(LPARAM lParam) { + /* get contact's country */ + int countryNumber = ServiceDetectContactOriginCountry((WPARAM)lParam,0);; + //use ExtraIconsService ? + if (myGlobals.ExtraIconsServiceExist) { + EXTRAICON ico; + ico.cbSize = sizeof(ico); + ico.hContact = (HANDLE)lParam; + ico.hExtraIcon = hExtraIconSvc; + ico.icoName = (char*)0; //preset + if(countryNumber!=0xFFFF || gFlagsOpts.bUseUnknownFlag) { + char szId[20]; + mir_snprintf(szId, SIZEOF(szId), (countryNumber==0xFFFF)?"%s_0x%X":"%s_%i","flags",countryNumber); /* buffer safe */ + ico.icoName = szId; + } + CallService(MS_EXTRAICON_SET_ICON, (WPARAM)&ico, 0); + } + //use Clist ExtraImageService + else if(gFlagsOpts.bShowExtraImgFlag) { + int index; + IconExtraColumn iec; + iec.cbSize = sizeof(iec); + iec.ColumnType = gFlagsOpts.idExtraColumn; + iec.hImage = INVALID_HANDLE_VALUE; //preset + /* get icon for contact */ + if(phExtraImageList!=NULL) { /* too early? */ + if(countryNumber!=0xFFFF || gFlagsOpts.bUseUnknownFlag) { + index = CountryNumberToIndex(countryNumber); + /* icon not add to clist extra image list? */ + if(phExtraImageList[index]==INVALID_HANDLE_VALUE) { + HICON hIcon=LoadFlag(countryNumber); // Returned HICON SHOULDN'T be destroyed, it is managed by IcoLib + if(hIcon!=NULL) { + phExtraImageList[index]=(HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON,(WPARAM)hIcon,0); + CallService(MS_SKIN2_RELEASEICON,(WPARAM)hIcon,0); /* does NULL check */ + } + } + iec.hImage=phExtraImageList[index]; + } + } + //Set icon for contact at needed column + CallService(MS_CLIST_EXTRA_SET_ICON,(WPARAM)lParam,(LPARAM)&iec); + } +} + +static void CALLBACK RemoveExtraImages(LPARAM lParam) { + register HANDLE hContact; + //use ExtraIconsService ? + if (myGlobals.ExtraIconsServiceExist) { + EXTRAICON ico; + ico.cbSize = sizeof(ico); + ico.hExtraIcon = hExtraIconSvc; + ico.icoName = (char *)0; /* invalidate icon for contact*/ + /* enum all contacts */ + for (hContact = DB::Contact::FindFirst(); hContact != NULL; hContact = DB::Contact::FindNext(hContact)) { + ico.hContact = hContact; + CallService(MS_EXTRAICON_SET_ICON, (WPARAM)&ico, 0); + } + } + //use Clist ExtraImageService + else { + IconExtraColumn iec; + iec.cbSize = sizeof(iec); + iec.ColumnType = gFlagsOpts.idExtraColumn; + iec.hImage = INVALID_HANDLE_VALUE; + /* enum all contacts */ + for (hContact = DB::Contact::FindFirst(); hContact != NULL; hContact = DB::Contact::FindNext(hContact)) { + /* invalidate icon for contact*/ + CallService(MS_CLIST_EXTRA_SET_ICON,(WPARAM)hContact,(LPARAM)&iec); + } + } +} + +// always call in context of main thread +void EnsureExtraImages() //garantieren - sicherstellen - updaten +{ + register HANDLE hContact; + //use Clist ExtraImageService? + if(!myGlobals.ExtraIconsServiceExist) { + BYTE idExtraColumnNew = DB::Setting::GetByte(MODNAMEFLAGS,"ExtraImgFlagColumn",SETTING_EXTRAIMGFLAGCOLUMN_DEFAULT); + if(idExtraColumnNew != gFlagsOpts.idExtraColumn) { + /* clear previous column */ + RemoveExtraImages(0); + gFlagsOpts.idExtraColumn = idExtraColumnNew; + /* clear new column */ + RemoveExtraImages(0); + } + } + /* enum all contacts */ + for (hContact = DB::Contact::FindFirst(); hContact != NULL; hContact = DB::Contact::FindNext(hContact)) { + /* update icon */ + CallFunctionBuffered(SetExtraImage,(LPARAM)hContact,TRUE,EXTRAIMAGE_REFRESHDELAY); + } +} + +static void CALLBACK UpdateExtraImages(LPARAM lParam) { + if(!lParam) + RemoveExtraImages(0); + else EnsureExtraImages(); + +/* if(!myGlobals.ExtraIconsServiceExist && !gFlagsOpts.bShowExtraImgFlag) + RemoveExtraImages(); + else EnsureExtraImages(); */ +} + +//hookProc ME_CLIST_EXTRA_LIST_REBUILD +static int OnCListRebuildIcons(WPARAM wParam,LPARAM lParam) { + OutputDebugStringA("REBUILD EXTRA\n"); + //use ExtraIconsService ? + if(myGlobals.ExtraIconsServiceExist) return 0; //delete ? + //use Clist ExtraImageService + if(phExtraImageList!=NULL) { + /* invalidate icons */ + for(int i=0;iszModule, "ExtraIcons") && + !lstrcmpA(dbcws->szSetting,"Slot_Flags") ){ + BOOL bEnable; + switch (dbcws->value.type) { + case DBVT_BYTE: + bEnable = dbcws->value.bVal != (BYTE)-1; + break; + case DBVT_WORD: + bEnable = dbcws->value.wVal != (WORD)-1; + break; + case DBVT_DWORD: + bEnable = dbcws->value.dVal != (DWORD)-1; + break; + default: + bEnable = -1; + break; + } + if(bEnable == -1) { + return 0; + } + else if(bEnable && !hApplyIconHook) { + hApplyIconHook = HookEvent(ME_CLIST_EXTRA_IMAGE_APPLY, OnCListApplyIcons); + } + else if(!bEnable && hApplyIconHook) { + UnhookEvent(hApplyIconHook); hApplyIconHook = NULL; + } + CallFunctionBuffered(UpdateExtraImages,(LPARAM)bEnable,FALSE,EXTRAIMAGE_REFRESHDELAY); + } + return 0; +} + +VOID SvcFlagsEnableExtraIcons(BYTE bColumn, BOOLEAN bUpdateDB) { + if (!myGlobals.HaveCListExtraIcons) return; + gFlagsOpts.bShowExtraImgFlag = (bColumn!=((BYTE)-1)); + if (bUpdateDB) { + if(gFlagsOpts.bShowExtraImgFlag) DB::Setting::WriteByte(MODNAMEFLAGS,"ExtraImgFlagColumn", bColumn); + DB::Setting::WriteByte(MODNAMEFLAGS,"ShowExtraImgFlag", bColumn!=(BYTE)-1); + } + + // Flags is on + if (gFlagsOpts.bShowExtraImgFlag) { + //use ExtraIconsService ? + if(myGlobals.ExtraIconsServiceExist) { + if(hExtraIconSvc == INVALID_HANDLE_VALUE) { + char szId[20]; + //get local langID for descIcon (try to use user local Flag as icon) + DWORD langid = 0; + int r = GetLocaleInfo( + LOCALE_USER_DEFAULT, + LOCALE_ICOUNTRY | LOCALE_RETURN_NUMBER , + (LPTSTR)&langid, sizeof(langid)/sizeof(TCHAR)); + if(!CallService(MS_UTILS_GETCOUNTRYBYNUMBER,langid,0)) langid = 1; + + EXTRAICON_INFO ico = {0}; + ico.cbSize = sizeof(ico); + ico.type = EXTRAICON_TYPE_ICOLIB; + ico.name = "Flags"; + ico.description = "Flags (uinfoex)"; + mir_snprintf(szId, SIZEOF(szId), (langid==0xFFFF)?"%s_0x%X":"%s_%i","flags",langid); /* buffer safe */ + ico.descIcon = szId; + hExtraIconSvc=(HANDLE)CallService(MS_EXTRAICON_REGISTER, (WPARAM)&ico, 0); + if(hExtraIconSvc) + hExtraIconSvcHook = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, OnExtraIconSvcChanged); + + } + } + //use Clist ExtraImageService + else { + if(phExtraImageList == NULL){ + phExtraImageList = (HANDLE*)mir_alloc(nCountriesCount*sizeof(HANDLE)); + /* invalidate icons */ + if(phExtraImageList!=NULL) + for(int i=0;im_hContact - (INT_PTR)p2->m_hContact); +} +static LIST gMsgWndList(10, CompareMsgWndData); + +static int CompareIconListData(const IconList* p1, const IconList* p2) +{ + return (int)((INT_PTR)p1->m_ID - (INT_PTR)p2->m_ID); +} +static OBJLIST gIListMW(10, CompareIconListData); + +IconList::IconList(StatusIconData *sid) { + m_StatusIconData.cbSize = sid->cbSize; + m_StatusIconData.szModule = mir_strdup(sid->szModule); + m_StatusIconData.dwId = sid->dwId; + m_StatusIconData.hIcon = CopyIcon(sid->hIcon); + m_StatusIconData.hIconDisabled = sid->hIconDisabled; + m_StatusIconData.flags = sid->flags; + m_StatusIconData.szTooltip = mir_strdup(sid->szTooltip); + + m_ID = sid->dwId; + CallService(MS_MSG_ADDICON,0,(LPARAM)sid); + +} +IconList::~IconList() { + mir_free(m_StatusIconData.szModule); + mir_free(m_StatusIconData.szTooltip); +} +// const char *pszName; // [Optional] Name of an icon registered with icolib to be used in GUI. +static __inline int MessageAPI_AddIcon(const char* pszName, const char* szModul/*StatusIconData *sid*/,int ID, int flags, const char* szTooltip) +{ + HICON hIcon = (HICON)CallService(MS_SKIN2_GETICON,(WPARAM)0/* =small 1=big*/,(LPARAM)pszName); + + StatusIconData sid = {0}; + sid.cbSize = sizeof(sid); + sid.szModule = (char*)szModul; + sid.dwId = (DWORD)ID; + sid.hIcon = (hIcon!=NULL)?CopyIcon(hIcon):NULL; + CallService(MS_SKIN2_RELEASEICON,(WPARAM)hIcon,0); /* does NULL check */ +// sid.hIconDisabled = sid.hIcon/*NULL*/; + sid.flags = 0; + sid.szTooltip = Translate((char*)CallService(MS_UTILS_GETCOUNTRYBYNUMBER,ID,0)); + + int res = -1; + IconList* p = new IconList(&sid); + if(!p->m_ID)delete p; + else res = gIListMW.insert(p); + if(res == -1)delete p; + return res; +} + +void CALLBACK UpdateStatusIcons(LPARAM lParam) { + if(!lParam) { + /* enum all opened message windows */ + for (int i = 0; i < gMsgWndList.getCount(); i++) + gMsgWndList[i]->FlagsIconUpdate(); + } + else { + int i = gMsgWndList.getIndex((MsgWndData*)&lParam); + if (i!= -1) gMsgWndList[i]->FlagsIconUpdate(); + } +} + +//hookProc ME_MSG_WINDOWEVENT +static int OnMsgWndEvent(WPARAM wParam,LPARAM lParam) { + MessageWindowEventData *msgwe=(MessageWindowEventData*)lParam; + /* sanity check */ + if(msgwe->hContact==NULL) + return 0; + + switch(msgwe->uType) { + case MSG_WINDOW_EVT_OPENING: + { + MsgWndData* msgwnd = gMsgWndList.find((MsgWndData*)&msgwe->hContact); + if(msgwnd == NULL) { + msgwnd = new MsgWndData(msgwe->hwndWindow, msgwe->hContact); + gMsgWndList.insert(msgwnd); + } + } + break; + + case MSG_WINDOW_EVT_CLOSE: + { + int i = gMsgWndList.getIndex((MsgWndData*)&msgwe->hContact); + if (i != -1) { + delete gMsgWndList[i]; + gMsgWndList.remove(i); + } + } + break; + } + return 0; +} + +//hookProc ME_SKIN2_ICONSCHANGED +static int OnStatusIconsChanged(WPARAM wParam,LPARAM lParam) { + if(myGlobals.MsgAddIconExist && gFlagsOpts.bShowStatusIconFlag) + CallFunctionBuffered(UpdateStatusIcons,0,FALSE,STATUSICON_REFRESHDELAY); + return 0; +} + +/*********************************************************************************************************** + * option page (not used yet) + ***********************************************************************************************************/ +static INT_PTR CALLBACK ExtraImgOptDlgProc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam) +{ + return FALSE; +} + +//hookProc ME_OPT_INITIALISE +static int ExtraImgOptInit(WPARAM wParam,LPARAM lParam) +{ + OPTIONSDIALOGPAGE odp = { 0 }; + return 0; +} + +/*********************************************************************************************************** + * misc functions + ***********************************************************************************************************/ +//hookProc ME_DB_CONTACT_SETTINGCHANGED +static int OnContactSettingChanged(WPARAM wParam,LPARAM lParam) { + if((HANDLE)wParam==NULL) return 0; + DBCONTACTWRITESETTING *dbcws=(DBCONTACTWRITESETTING*)lParam; + + /* user details update */ + if(/*!lstrcmpA(dbcws->szSetting,"RealIP") || */ + !lstrcmpA(dbcws->szSetting,SET_CONTACT_COUNTRY) || + !lstrcmpA(dbcws->szSetting,SET_CONTACT_ORIGIN_COUNTRY) || + !lstrcmpA(dbcws->szSetting,SET_CONTACT_COMPANY_COUNTRY)) + { + /* Extra Image */ + if(myGlobals.HaveCListExtraIcons) + CallFunctionBuffered(SetExtraImage,(LPARAM)wParam,TRUE,EXTRAIMAGE_REFRESHDELAY); + /* Status Icon */ + if(hMsgWndEventHook) { + int i = gMsgWndList.getIndex((MsgWndData*)&wParam); + if (i != -1) { + gMsgWndList[i]->ContryIDchange((int)ServiceDetectContactOriginCountry(wParam,0)); + gMsgWndList[i]->FlagsIconUpdate(); + } + } + } + return 0; +} + + +/*********************************************************************************************************** + * module loading & unloading + ***********************************************************************************************************/ + +/** + * This function initially loads all required stuff for Flags. + * + * @param none + * + * @return nothing + **/ +void SvcFlagsLoadModule() +{ + PrepareBufferedFunctions(); + InitCountryListExt(); /* hack to replace core country list */ + if(CallService(MS_UTILS_GETCOUNTRYLIST,(WPARAM)&nCountriesCount,(LPARAM)&countries)) + nCountriesCount=0; + InitIcons(); /* load in iconlib */ + //InitIpToCountry(); /* not implementet */ + myCreateServiceFunction(MS_FLAGS_DETECTCONTACTORIGINCOUNTRY,ServiceDetectContactOriginCountry); + //init settings + gFlagsOpts.bShowExtraImgFlag = DB::Setting::GetByte(MODNAMEFLAGS,"ShowExtraImgFlag", SETTING_SHOWEXTRAIMGFLAG_DEFAULT); + gFlagsOpts.bUseUnknownFlag = DB::Setting::GetByte(MODNAMEFLAGS,"UseUnknownFlag", SETTING_USEUNKNOWNFLAG_DEFAULT); + gFlagsOpts.idExtraColumn = DB::Setting::GetByte(MODNAMEFLAGS,"ExtraImgFlagColumn", SETTING_EXTRAIMGFLAGCOLUMN_DEFAULT); + gFlagsOpts.bShowStatusIconFlag = DB::Setting::GetByte(MODNAMEFLAGS,"ShowStatusIconFlag", SETTING_SHOWSTATUSICONFLAG_DEFAULT); + + hOptInitHook = HookEvent(ME_OPT_INITIALISE,ExtraImgOptInit); + hIconsChangedHook = HookEvent(ME_SKIN2_ICONSCHANGED,OnStatusIconsChanged); +} + +/** + * This function is called by Miranda just after loading all system modules. + * + * @param none + * + * @return nothing + **/ +void SvcFlagsOnModulesLoaded() { + //use ExtraIconsService ? + if ( myGlobals.ExtraIconsServiceExist) { + SvcFlagsEnableExtraIcons(DB::Setting::GetByte(SET_CLIST_EXTRAICON_FLAGS2, 0), FALSE); + } + //use Clist ExtraImageService + else { + SvcFlagsEnableExtraIcons(gFlagsOpts.bShowExtraImgFlag? gFlagsOpts.idExtraColumn : -1, FALSE); + } + /* Status Icon */ + if(myGlobals.MsgAddIconExist) + hMsgWndEventHook = HookEvent(ME_MSG_WINDOWEVENT, OnMsgWndEvent); +} + +/** + * This function unloads the module. + * + * @param none + * + * @return nothing + **/ +void SvcFlagsUnloadModule() { + KillBufferedFunctions(); + //Uninit ExtraImg + UnhookEvent(hRebuildIconsHook); + UnhookEvent(hApplyIconHook); + UnhookEvent(hIconsChangedHook); + UnhookEvent(hExtraIconSvcHook); + mir_free(phExtraImageList); /* does NULL check */ + //Uninit message winsow + UnhookEvent(hMsgWndEventHook); + for(int i = 0; i < gMsgWndList.getCount(); i++) { + //this should not happen + delete gMsgWndList[i]; + gMsgWndList.remove(i); + } + gMsgWndList.destroy(); + gIListMW.destroy(); + //Uninit misc + UnhookEvent(hSettingChangedHook); + UnhookEvent(hOptInitHook); + UninitIcons(); + + //UninitIpToCountry(); /* not implementet */ +} + -- cgit v1.2.3