#define PLUGIN_NAME L"Nullsoft Tray Control" #define PLUGIN_VERSION L"2.49" // Winamp general purpose plug-in mini-SDK // Copyright (C) 1997, Justin Frankel/Nullsoft // Modifications and useability enhancements by DrO aka Darren Owen 2006-2014 #include #include #include #include "../winamp/gen.h" #include "../winamp/wa_ipc.h" #include "../winamp/ipc_pe.h" #include "resource.h" #include "winampcmd.h" #include "api__gen_tray.h" #include #ifndef _DEBUG BOOL WINAPI _DllMainCRTStartup(HINSTANCE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) { DisableThreadLibraryCalls(hInst); return TRUE; } #endif #define NUM_ICONS 8 #define FOURWAY_NUM 7 #define SYSTRAY_ICON_BASE 1024 // used for Win7+ usage inorder to get the direct location of the icon instead of the prior hacks (thanks MS!) typedef HRESULT (WINAPI *SHELL_NOTIFYICONGETRECT)(const NOTIFYICONIDENTIFIER* identifier, RECT* iconLocation); SHELL_NOTIFYICONGETRECT g_Shell_NotifyIconGetRect = 0; // Use a guid to uniquely identify our icon class __declspec(uuid("B4E5FE9B-6A22-450e-9565-941EF50CFEEB")) CompactIcon; // wasabi based services for localisation support api_service *WASABI_API_SVC = 0; api_language *WASABI_API_LNG = 0; HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0; int config_enabled = 0, xporhigher = 0, custom_enabled = 0, winver = 0, flip = 0, on = 1, update_file = 0, isX64 = 0, no_uninstall = 1, dlg_init = 0; UINT s_uTaskbarRestart=0; HWND configwnd = 0; WNDPROC lpWndProcOld = 0; HICON Icons[NUM_ICONS] = {0}, dummyIcon = 0; HBITMAP compact = 0; fileinfo2W file = {0}; wchar_t ico_pack[MAX_PATH] = {0}, ico_pack_base[MAX_PATH] = {0}, ico_pack_safe[MAX_PATH] = {0}, wa_path[MAX_PATH] = {0}, *ini_file = 0, szDescription[256] = {0}; int tips[NUM_ICONS] = { IDS_PREVIOUS_TRACK, IDS_PLAY_PAUSE, IDS_STOP, IDS_NEXT_TRACK, IDS_OPEN_FILE, IDS_COMPACT_MODE, IDS_DECREASE_VOLUME, IDS_INCREASE_VOLUME, }; int tips_ex[NUM_ICONS] = { IDS_HOLD_CTRL, IDS_HOLD_CTRL, IDS_HOLD_SHIFT, -1, -1, // IDS_WIN2K_PLUS, -1, IDS_CTRL_TO_DECREASE, IDS_CTRL_TO_INCREASE, }; LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); BOOL CALLBACK ConfigProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam); HICON CreateInternalIcon(void); int FileExists(char* filename); void config(void); void quit(void); int init(void); void config_write(); void config_read(); extern "C" winampGeneralPurposePlugin plugin = { GPPHDR_VER_U, "nullsoft(gen_tray.dll)", init, config, quit, }; extern "C" __declspec(dllexport) winampGeneralPurposePlugin * winampGetGeneralPurposePlugin() { return &plugin; } HWND GetPlaylistWnd(HWND winamp){ HWND pl_wnd = 0; // get the playlist editor window (either v2.9x method or the older // for compatibility incase < 2.9x are used if(SendMessage(winamp,WM_WA_IPC,0,IPC_GETVERSION) >= 0x2900) { pl_wnd = (HWND)SendMessage(winamp,WM_WA_IPC,IPC_GETWND_PE,IPC_GETWND); } if(!pl_wnd) { pl_wnd = FindWindow(L"Winamp PE",0); } return pl_wnd; } void FormCompactText(wchar_t* szTip, int szTipLength){ int got = 0; // only update if we really have to (to better mimick Winamp's title behaviour, etc) // otherwise we query in all cases which can often reflect what appears to be the wrong information since // the current playlist entry is altered, etc on playlist modification hence an incorrect observation if(!update_file){ update_file = 1; file.fileindex = (int)SendMessage(GetPlaylistWnd(plugin.hwndParent),WM_WA_IPC,IPC_PE_GETCURINDEX,0); got = (int)SendMessage(GetPlaylistWnd(plugin.hwndParent),WM_WA_IPC,IPC_PE_GETINDEXTITLEW,(LPARAM)&file); } // if it returns 0 then track information was received if(!got && file.filetitle[0]){ int time = (int)SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETOUTPUTTIME); wchar_t buf[MAX_PATH*2] = {0}, temp[1024] = {0}, *t = temp, *p = 0; int over = 0, state = 0, blah = 0; wchar_t stateStr[32] = {0}; switch(SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_ISPLAYING)){ case 0: WASABI_API_LNGSTRINGW_BUF(IDS_STOPPED_STR,stateStr,32); state = lstrlen(stateStr); break; case 3: WASABI_API_LNGSTRINGW_BUF(IDS_PAUSED_STR,stateStr,32); state = lstrlen(stateStr); break; } p = file.filetitle; while(p && *p){ *t++ = *p++; if(*(p-1) == '&'){ *t++ = '&'; *t++ = '&'; } } *t = 0; StringCchPrintf(buf,MAX_PATH*2,L"%d. %s",(file.fileindex)+1,file.filetitle); over = lstrlen(buf); if(over > szTipLength - 1){over = szTipLength - 1;} lstrcpyn(szTip,buf,szTipLength); if(time != -1){ time = time/1000; if(file.filelength[0]){ StringCchPrintf(buf,MAX_PATH*2,L" [%02d:%02d/%s]",(time/60),time%60,file.filelength); blah = lstrlen(buf); } else{ StringCchPrintf(buf,MAX_PATH*2,L" [%02d:%02d]",(time/60),time%60); blah = lstrlen(buf); } } if((over + blah + state) > szTipLength){ int adj = szTipLength-blah-state-1; szTip[adj] = 0; szTip[adj-1] = L'.'; szTip[adj-2] = L'.'; szTip[adj-3] = L'.'; } if(time != -1){ StringCchCat(szTip,szTipLength,buf); } if(state){ StringCchCat(szTip,szTipLength,stateStr); } } // fall back to the Winamp version just incase else{ wchar_t temp[16] = {0}; StringCchPrintf(temp,16,L"%X",SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSION)); StringCchPrintf(szTip,szTipLength,L"Winamp %c.%s",temp[0],&temp[2]); } } void free_icons(void){ int i = 0; for (i = 0; i < NUM_ICONS; i++) { if( Icons[i] ) { DestroyIcon(Icons[i]); Icons[i] = 0; } } if(dummyIcon) { DestroyIcon(dummyIcon); dummyIcon = 0; } if(compact) { DeleteObject(compact); } } void do_icons(int force) { static int l=0; int i=NUM_ICONS; if (l == config_enabled && !force) return; if( force ) free_icons(); while (i--) { if (l & (1<-1:i < NUM_ICONS); (xporhigher?i --:i ++)) { if (config_enabled & (1<