/* Miranda IM: the free IM client for Microsoft* Windows* Copyright 2000-2009 Miranda ICQ/IM project, all portions of this codebase are copyrighted to the people listed in contributors.txt. 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. */ #include "..\..\core\commonheaders.h" struct SoundItem { char* name; TCHAR* section; TCHAR* description; char* tempFile; }; static BOOL bModuleInitialized = FALSE; static struct SoundItem *soundList = NULL; static int soundCount; static HANDLE hPlayEvent = NULL; static INT_PTR ServiceSkinAddNewSound(WPARAM, LPARAM lParam) { SKINSOUNDDESCEX *ssd = ( SKINSOUNDDESCEX* )lParam; switch( ssd->cbSize ) { case sizeof( SKINSOUNDDESCEX ): case SKINSOUNDDESC_SIZE_V1: case SKINSOUNDDESC_SIZE_V2: break; default: return 1; } if ( ssd->pszName == NULL || ssd->pszDescription == NULL) return 1; DBVARIANT dbv; DWORD dwFlags = ( ssd->cbSize == sizeof(SKINSOUNDDESCEX)) ? ssd->dwFlags : 0; soundList=(struct SoundItem*)mir_realloc(soundList,sizeof(struct SoundItem)*(soundCount+1)); SoundItem* item = &soundList[soundCount++]; item->name = mir_strdup( ssd->pszName ); item->tempFile = NULL; #if defined( _UNICODE ) TCHAR* ptszDefaultFile; if ( dwFlags & SSDF_UNICODE ) { item->description = mir_tstrdup( TranslateTS( ssd->ptszDescription )); item->section = mir_tstrdup( TranslateTS( ssd->cbSize != SKINSOUNDDESC_SIZE_V1 && ssd->pszSection != NULL ? ssd->ptszSection : _T("Other"))); ptszDefaultFile = mir_tstrdup( ssd->ptszDefaultFile ); } else { item->description = LangPackPcharToTchar( ssd->pszDescription ); item->section = LangPackPcharToTchar( ssd->cbSize != SKINSOUNDDESC_SIZE_V1 && ssd->pszSection != NULL ? ssd->pszSection : "Other" ); ptszDefaultFile = mir_a2t( ssd->pszDefaultFile ); } if ( ptszDefaultFile ) { if ( DBGetContactSettingString(NULL, "SkinSounds", item->name, &dbv)) DBWriteContactSettingTString(NULL, "SkinSounds", item->name, ptszDefaultFile); else DBFreeVariant(&dbv); mir_free( ptszDefaultFile ); } #else item->description = mir_tstrdup( TranslateTS( ssd->pszDescription )); item->section = mir_tstrdup( TranslateTS( ssd->cbSize != SKINSOUNDDESC_SIZE_V1 && ssd->pszSection != NULL ? ssd->pszSection : "Other" )); if ( ssd->pszDefaultFile ) { if ( DBGetContactSettingString(NULL, "SkinSounds", item->name, &dbv)) DBWriteContactSettingString(NULL, "SkinSounds", item->name, ssd->pszDefaultFile); else DBFreeVariant(&dbv); } #endif return 0; } static int SkinPlaySoundDefault(WPARAM wParam, LPARAM lParam) { char * pszFile = (char *) lParam; if ( pszFile && (DBGetContactSettingByte(NULL,"Skin","UseSound",0) || (int)wParam==1)) PlaySoundA(pszFile, NULL, SND_ASYNC | SND_FILENAME | SND_NOWAIT); return 0; } static INT_PTR ServiceSkinPlaySound(WPARAM, LPARAM lParam) { char* pszSoundName = ( char* )lParam; int j; for (j=0; j<soundCount; j++) { if ( pszSoundName && strcmp( soundList[j].name, pszSoundName ) == 0) { if (DBGetContactSettingByte(NULL, "SkinSoundsOff", pszSoundName, 0)==0) { DBVARIANT dbv; if (DBGetContactSettingString(NULL, "SkinSounds", pszSoundName, &dbv)==0) { char szFull[MAX_PATH]; pathToAbsolute(dbv.pszVal, szFull, NULL); NotifyEventHooks(hPlayEvent, 0, (LPARAM)szFull); DBFreeVariant(&dbv); } } return 0; } } return 1; } static HTREEITEM FindNamedTreeItemAtRoot(HWND hwndTree, const TCHAR* name) { TVITEM tvi; TCHAR str[128]; tvi.mask = TVIF_TEXT; tvi.pszText = str; tvi.cchTextMax = SIZEOF(str); tvi.hItem = TreeView_GetRoot(hwndTree); while( tvi.hItem != NULL ) { TreeView_GetItem( hwndTree, &tvi ); if ( !_tcsicmp( str, name )) return tvi.hItem; tvi.hItem = TreeView_GetNextSibling( hwndTree, tvi.hItem ); } return NULL; } #define DM_REBUILD_STREE (WM_USER+1) #define DM_HIDEPANE (WM_USER+2) #define DM_SHOWPANE (WM_USER+3) #define DM_CHECKENABLED (WM_USER+4) INT_PTR CALLBACK DlgProcSoundOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { static HWND hwndTree = NULL; switch (msg) { case WM_DESTROY: ImageList_Destroy(TreeView_GetImageList(hwndTree, TVSIL_STATE)); break; case WM_INITDIALOG: TranslateDialogDefault(hwndDlg); hwndTree = GetDlgItem(hwndDlg, IDC_SOUNDTREE); SetWindowLongPtr(hwndTree,GWL_STYLE,GetWindowLongPtr(hwndTree,GWL_STYLE)|TVS_NOHSCROLL|TVS_CHECKBOXES); SendMessage(hwndDlg, DM_HIDEPANE, 0, 0); SendMessage(hwndDlg, DM_REBUILD_STREE, 0, 0); TreeView_SetItemState(hwndTree, 0, TVIS_SELECTED, TVIS_SELECTED); CheckDlgButton(hwndDlg, IDC_ENABLESOUNDS, DBGetContactSettingByte(NULL, "Skin", "UseSound", 0)); SendMessage(hwndDlg, DM_CHECKENABLED, 0, 0); return TRUE; case DM_REBUILD_STREE: TreeView_SelectItem(hwndTree, NULL); ShowWindow(hwndTree, SW_HIDE); TreeView_DeleteAllItems(hwndTree); { TVINSERTSTRUCT tvis; int i; tvis.hParent = NULL; tvis.hInsertAfter = TVI_SORT; tvis.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM; tvis.item.state = tvis.item.stateMask = TVIS_EXPANDED; for ( i=0; i < soundCount; i++ ) { tvis.item.stateMask = TVIS_EXPANDED; tvis.item.state = TVIS_EXPANDED; tvis.hParent = FindNamedTreeItemAtRoot( hwndTree, soundList[i].section ); if ( tvis.hParent == NULL ) { tvis.item.lParam = -1; tvis.item.pszText = soundList[i].section; tvis.hParent = tvis.item.hItem = TreeView_InsertItem( hwndTree, &tvis ); tvis.item.stateMask = TVIS_STATEIMAGEMASK; tvis.item.state = INDEXTOSTATEIMAGEMASK(0); TreeView_SetItem( hwndTree, &tvis.item ); } tvis.item.stateMask = TVIS_STATEIMAGEMASK; tvis.item.state = INDEXTOSTATEIMAGEMASK(!DBGetContactSettingByte(NULL,"SkinSoundsOff",soundList[i].name,0)?2:1); tvis.item.lParam = i; tvis.item.pszText = soundList[i].description; TreeView_InsertItem( hwndTree, &tvis ); } } { TVITEM tvi; tvi.hItem = TreeView_GetRoot(hwndTree); while ( tvi.hItem != NULL ) { tvi.mask = TVIF_PARAM | TVIF_HANDLE | TVIF_STATE; TreeView_GetItem(hwndTree, &tvi); if ( tvi.lParam == -1 ) TreeView_SetItemState(hwndTree, tvi.hItem, INDEXTOSTATEIMAGEMASK(0), TVIS_STATEIMAGEMASK); tvi.hItem=TreeView_GetNextSibling(hwndTree,tvi.hItem); } } ShowWindow(hwndTree, SW_SHOW); break; case DM_HIDEPANE: ShowWindow(GetDlgItem(hwndDlg, IDC_SGROUP), SW_HIDE); ShowWindow(GetDlgItem(hwndDlg, IDC_NAME), SW_HIDE); ShowWindow(GetDlgItem(hwndDlg, IDC_NAMEVAL), SW_HIDE); ShowWindow(GetDlgItem(hwndDlg, IDC_SLOC), SW_HIDE); ShowWindow(GetDlgItem(hwndDlg, IDC_LOCATION), SW_HIDE); ShowWindow(GetDlgItem(hwndDlg, IDC_CHANGE), SW_HIDE); ShowWindow(GetDlgItem(hwndDlg, IDC_PREVIEW), SW_HIDE); ShowWindow(GetDlgItem(hwndDlg, IDC_GETMORE), SW_HIDE); break; case DM_SHOWPANE: ShowWindow(GetDlgItem(hwndDlg, IDC_SGROUP), SW_SHOW); ShowWindow(GetDlgItem(hwndDlg, IDC_NAME), SW_SHOW); ShowWindow(GetDlgItem(hwndDlg, IDC_NAMEVAL), SW_SHOW); ShowWindow(GetDlgItem(hwndDlg, IDC_SLOC), SW_SHOW); ShowWindow(GetDlgItem(hwndDlg, IDC_LOCATION), SW_SHOW); ShowWindow(GetDlgItem(hwndDlg, IDC_CHANGE), SW_SHOW); ShowWindow(GetDlgItem(hwndDlg, IDC_PREVIEW), SW_SHOW); ShowWindow(GetDlgItem(hwndDlg, IDC_GETMORE), SW_SHOW); break; case DM_CHECKENABLED: EnableWindow(GetDlgItem(hwndDlg, IDC_SOUNDTREE), IsDlgButtonChecked(hwndDlg, IDC_ENABLESOUNDS)); if (!IsDlgButtonChecked(hwndDlg, IDC_ENABLESOUNDS)) SendMessage(hwndDlg, DM_HIDEPANE, 0, 0); else if (TreeView_GetSelection(hwndTree)&&TreeView_GetParent(hwndTree, TreeView_GetSelection(hwndTree))) SendMessage(hwndDlg, DM_SHOWPANE, 0, 0); break; case WM_COMMAND: if ( LOWORD(wParam) == IDC_ENABLESOUNDS ) SendMessage(hwndDlg, DM_CHECKENABLED, 0, 0); if ( LOWORD(wParam) == IDC_PREVIEW ) { TVITEM tvi; HTREEITEM hti; ZeroMemory(&tvi,sizeof(tvi)); ZeroMemory(&hti,sizeof(hti)); hti=TreeView_GetSelection(hwndTree); if (hti==NULL) break; tvi.mask=TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM|TVIF_TEXT; tvi.hItem = hti; if (TreeView_GetItem(hwndTree, &tvi)==FALSE) break; if (tvi.lParam==-1) break; if (soundList[tvi.lParam].tempFile) NotifyEventHooks(hPlayEvent, 1, (LPARAM)soundList[tvi.lParam].tempFile); else { DBVARIANT dbv; if (!DBGetContactSettingString(NULL,"SkinSounds",soundList[tvi.lParam].name,&dbv)) { char szPathFull[MAX_PATH]; pathToAbsolute(dbv.pszVal, szPathFull, NULL); NotifyEventHooks(hPlayEvent, 1, (LPARAM)szPathFull); DBFreeVariant(&dbv); } } break; } if ( LOWORD( wParam ) == IDC_CHANGE ) { char str[MAX_PATH] = "", strFull[MAX_PATH], strdir[MAX_PATH]="", filter[MAX_PATH]; OPENFILENAMEA ofn; TVITEM tvi; HTREEITEM hti; ZeroMemory(&tvi,sizeof(tvi)); ZeroMemory(&hti,sizeof(hti)); hti=TreeView_GetSelection(hwndTree); if (hti==NULL) break; tvi.mask=TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM|TVIF_TEXT; tvi.hItem = hti; if (TreeView_GetItem(hwndTree, &tvi)==FALSE) break; if (tvi.lParam==-1) break; if (soundList[tvi.lParam].tempFile) mir_snprintf(strFull, SIZEOF(strFull), "%s", soundList[tvi.lParam].tempFile); else { if (DBGetContactSettingByte(NULL, "SkinSoundsOff", soundList[tvi.lParam].name, 0)==0) { DBVARIANT dbv; if (DBGetContactSettingString(NULL, "SkinSounds", soundList[tvi.lParam].name, &dbv)==0) { pathToAbsolute(dbv.pszVal, strdir, NULL); DBFreeVariant(&dbv); } } } mir_snprintf(strFull, SIZEOF(strFull), "%s", soundList[tvi.lParam].tempFile?soundList[tvi.lParam].tempFile:""); pathToAbsolute(strFull, strdir, NULL); ZeroMemory(&ofn, sizeof(ofn)); mir_snprintf(filter, SIZEOF(filter), "%s (*.wav; *.mp3; *.ogg; *.flac)%c*.WAV; *.MP3; *.OGG; *.FLAC%c%s (*)%c*%c", Translate("Sound Files"), 0, 0, Translate("All Files"), 0, 0); ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; ofn.hwndOwner = GetParent(hwndDlg); ofn.hInstance = NULL; ofn.lpstrFilter = filter; { char* slash = strrchr(strdir, '\\'); if (slash) { *slash = 0; ofn.lpstrInitialDir = strdir; } } ofn.lpstrFile = str; ofn.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_EXPLORER|OFN_LONGNAMES|OFN_NOCHANGEDIR; ofn.nMaxFile = SIZEOF(str); ofn.nMaxFileTitle = MAX_PATH; ofn.lpstrDefExt = "wav"; if (!GetOpenFileNameA(&ofn)) break; CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)str, (LPARAM)strFull); soundList[tvi.lParam].tempFile = mir_strdup(strFull); SetDlgItemTextA(hwndDlg, IDC_LOCATION, strFull); } if (LOWORD(wParam)==IDC_GETMORE) { CallService(MS_UTILS_OPENURL,1,(LPARAM)"http://addons.miranda-im.org/index.php?action=display&id=5"); break; } if (LOWORD(wParam)==IDC_LOCATION) { break; } SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); break; case WM_NOTIFY: switch(((LPNMHDR)lParam)->idFrom) { case 0: if (((LPNMHDR)lParam)->code == PSN_APPLY) { int i; DBWriteContactSettingByte(NULL, "Skin", "UseSound", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_ENABLESOUNDS)); for ( i=0; i < soundCount; i++ ) if ( soundList[i].tempFile ) DBWriteContactSettingString(NULL,"SkinSounds",soundList[i].name,soundList[i].tempFile); { TVITEM tvi,tvic; tvi.hItem = TreeView_GetRoot(hwndTree); while ( tvi.hItem != NULL ) { tvi.mask = TVIF_PARAM | TVIF_HANDLE | TVIF_STATE; TreeView_GetItem(hwndTree, &tvi); if ( tvi.lParam == -1 ) { tvic.hItem = TreeView_GetChild(hwndTree, tvi.hItem); while ( tvic.hItem != NULL ) { tvic.mask = TVIF_PARAM | TVIF_HANDLE | TVIF_STATE; TreeView_GetItem(hwndTree, &tvic); if ((( tvic.state & TVIS_STATEIMAGEMASK ) >> 12 == 2 )) { DBCONTACTGETSETTING cgs; cgs.szModule = "SkinSoundsOff"; cgs.szSetting = soundList[tvic.lParam].name; CallService(MS_DB_CONTACT_DELETESETTING,(WPARAM)(HANDLE)NULL,(LPARAM)&cgs); } else DBWriteContactSettingByte(NULL,"SkinSoundsOff",soundList[tvic.lParam].name,1); tvic.hItem=TreeView_GetNextSibling(hwndTree,tvic.hItem); } } tvi.hItem=TreeView_GetNextSibling(hwndTree,tvi.hItem); } } return TRUE; } break; case IDC_SOUNDTREE: switch(((NMHDR*)lParam)->code) { case TVN_SELCHANGEDA: { NMTREEVIEW *pnmtv = (NMTREEVIEW*)lParam; TVITEM tvi = pnmtv->itemNew; if (tvi.lParam==-1) { SendMessage(hwndDlg, DM_HIDEPANE, 0, 0); } else { TCHAR buf[256]; DBVARIANT dbv; mir_sntprintf(buf, SIZEOF(buf), _T("%s: %s"), soundList[tvi.lParam].section, soundList[tvi.lParam].description); SetDlgItemText(hwndDlg, IDC_NAMEVAL, buf); if (soundList[tvi.lParam].tempFile) SetDlgItemTextA(hwndDlg, IDC_LOCATION, soundList[tvi.lParam].tempFile); else if (!DBGetContactSettingString(NULL,"SkinSounds",soundList[tvi.lParam].name,&dbv)) { SetDlgItemTextA(hwndDlg, IDC_LOCATION, dbv.pszVal); DBFreeVariant(&dbv); } else SetDlgItemText(hwndDlg, IDC_LOCATION, TranslateT("<not specified>")); SendMessage(hwndDlg, DM_SHOWPANE, 0, 0); } } break; case TVN_KEYDOWN: { NMTVKEYDOWN* ptkd = (NMTVKEYDOWN*)lParam; if (ptkd&&ptkd->wVKey==VK_SPACE&&TreeView_GetSelection(ptkd->hdr.hwndFrom)) SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); } break; case NM_CLICK: { TVHITTESTINFO hti; hti.pt.x=(short)LOWORD(GetMessagePos()); hti.pt.y=(short)HIWORD(GetMessagePos()); ScreenToClient(((LPNMHDR)lParam)->hwndFrom,&hti.pt); if (TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom,&hti)) if (hti.flags&TVHT_ONITEM) if (hti.flags&TVHT_ONITEMSTATEICON) if (TreeView_GetParent(hwndTree, hti.hItem)!=NULL) SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); break; } } break; } break; } return FALSE; } static UINT iconsExpertOnlyControls[]={IDC_IMPORT}; static int SkinOptionsInit(WPARAM wParam, LPARAM) { OPTIONSDIALOGPAGE odp = { 0 }; odp.cbSize = sizeof(odp); odp.position = -200000000; odp.hInstance = hMirandaInst; odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SOUND); odp.pszGroup = LPGEN("Customize"); odp.pszTitle = LPGEN("Sounds"); odp.pfnDlgProc = DlgProcSoundOpts; odp.flags = ODPF_BOLDGROUPS; CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp ); return 0; } static int SkinSystemModulesLoaded(WPARAM, LPARAM) { HookEvent(ME_OPT_INITIALISE,SkinOptionsInit); return 0; } int LoadSkinSounds(void) { bModuleInitialized = TRUE; soundList=NULL; soundCount=0; CreateServiceFunction(MS_SKIN_ADDNEWSOUND,ServiceSkinAddNewSound); CreateServiceFunction(MS_SKIN_PLAYSOUND,ServiceSkinPlaySound); HookEvent(ME_SYSTEM_MODULESLOADED,SkinSystemModulesLoaded); hPlayEvent=CreateHookableEvent(ME_SKIN_PLAYINGSOUND); SetHookDefaultForHookableEvent(hPlayEvent, SkinPlaySoundDefault); return 0; } void UnloadSkinSounds(void) { int i; if ( !bModuleInitialized ) return; for (i=0;i<soundCount;i++) { mir_free(soundList[i].name); mir_free(soundList[i].section); mir_free(soundList[i].description); if (soundList[i].tempFile) mir_free(soundList[i].tempFile); } if (soundCount) mir_free(soundList); }