#include "common.h" int upCount, total = 0; size_t list_size = 0; HANDLE mainThread; HANDLE hWakeEvent = 0; // thread protected variables CRITICAL_SECTION thread_finished_cs, list_changed_cs, data_list_cs; bool thread_finished = false, list_changed = false; PINGLIST data_list; HANDLE status_update_thread = 0; HWND hpwnd = 0, list_hwnd, hwnd_clist = 0; int frame_id = -1; HBRUSH tbrush = 0; FontIDT font_id; ColourIDT bk_col_id; HFONT hFont = 0; COLORREF bk_col = RGB(255, 255, 255); //////////////// #define TM_AUTOALPHA 1 static int transparentFocus=1; ///////////////// bool get_thread_finished() { Lock(&thread_finished_cs, "get_thread_finished"); bool retval = thread_finished; Unlock(&thread_finished_cs); return retval; } void set_thread_finished(bool f) { Lock(&thread_finished_cs, "set_thread_finished"); thread_finished = f; Unlock(&thread_finished_cs); } bool get_list_changed() { Lock(&list_changed_cs, "get_list_changed"); bool retval = list_changed; Unlock(&list_changed_cs); return retval; } void set_list_changed(bool f) { Lock(&list_changed_cs, "set_list_changed"); list_changed = f; Unlock(&list_changed_cs); } void SetProtoStatus(TCHAR *pszLabel, char *pszProto, int if_status, int new_status) { if(strcmp(pszProto, Translate("")) == 0) { int num_protocols; PROTOACCOUNT **pppDesc; ProtoEnumAccounts(&num_protocols,&pppDesc); for(int i = 0; i < num_protocols; i++) { SetProtoStatus(pszLabel, pppDesc[i]->szModuleName, if_status, new_status); } } else { if(ProtoServiceExists(pszProto, PS_GETSTATUS)) { if(ProtoCallService(pszProto, PS_GETSTATUS, 0, 0) == if_status) { if(options.logging) { TCHAR buf[1024]; mir_sntprintf(buf, 1024, TranslateT("%s - setting status of protocol '%S' (%d)"), pszLabel, pszProto, new_status); CallService(PLUG "/Log", (WPARAM)buf, 0); } ProtoCallService(pszProto, PS_SETSTATUS, new_status, 0); } } } } DWORD WINAPI sttCheckStatusThreadProc( void *vp) { clock_t start_t = clock(), end_t; while (!get_thread_finished()) { end_t = clock(); int wait = (int)((options.ping_period - ((end_t - start_t) / (double)CLOCKS_PER_SEC)) * 1000); if (wait > 0) WaitForSingleObjectEx(hWakeEvent, wait, TRUE); if(get_thread_finished()) break; start_t = clock(); bool timeout = false; bool reply = false; int count = 0; PINGADDRESS pa; HistPair history_entry; Lock(&data_list_cs, "ping thread loop start"); set_list_changed(false); size_t size = data_list.size(); Unlock(&data_list_cs); int index = 0; for(; index < size; index++) { Lock(&data_list_cs, "ping thread loop start"); int c = 0; for (pinglist_it i = data_list.begin(); i != data_list.end() && c <= index; ++i, c++) { if (c == index) { // copy just what we need - i.e. not history, not command pa.get_status = i->get_status; pa.item_id = i->item_id; pa.miss_count = i->miss_count; pa.port = i->port; _tcsncpy(pa.pszLabel, i->pszLabel, MAX_PINGADDRESS_STRING_LENGTH); _tcsncpy(pa.pszName, i->pszName, MAX_PINGADDRESS_STRING_LENGTH); strncpy(pa.pszProto, i->pszProto, MAX_PINGADDRESS_STRING_LENGTH); pa.set_status = i->set_status; pa.status = i->status; break; } } Unlock(&data_list_cs); if(get_thread_finished()) break; if(get_list_changed()) break; if(pa.status != PS_DISABLED) { if(!options.no_test_icon) { Lock(&data_list_cs, "ping thread loop start"); for(pinglist_it i = data_list.begin(); i != data_list.end(); ++i) { if(i->item_id == pa.item_id) { i->status = PS_TESTING; } } Unlock(&data_list_cs); InvalidateRect(list_hwnd, 0, FALSE); } CallService(PLUG "/Ping", 0, (LPARAM)&pa); if(get_thread_finished()) break; if(get_list_changed()) break; Lock(&data_list_cs, "ping thread loop start"); for(pinglist_it i = data_list.begin(); i != data_list.end(); ++i) { if(i->item_id == pa.item_id) { i->responding = pa.responding; i->round_trip_time = pa.round_trip_time; history_entry.first = i->round_trip_time; history_entry.second = time(0); history_map[i->item_id].push_back(history_entry); // maintain history (-1 represents no response) while(history_map[i->item_id].size() >= MAX_HISTORY) //history_map[i->item_id].pop_front(); history_map[i->item_id].remove(history_map[i->item_id].begin().val()); if(pa.responding) { if(pa.miss_count > 0) pa.miss_count = -1; else pa.miss_count--; pa.status = PS_RESPONDING; } else { if(pa.miss_count < 0) pa.miss_count = 1; else pa.miss_count++; pa.status = PS_NOTRESPONDING; } i->miss_count = pa.miss_count; i->status = pa.status; break; } } Unlock(&data_list_cs); if(pa.responding) { count++; if(pa.miss_count == -1 - options.retries || (((-pa.miss_count) % (options.retries + 1)) == 0 && !options.block_reps)) { reply = true; if(options.show_popup2 && ServiceExists(MS_POPUP_SHOWMESSAGE)) { ShowPopup(TranslateT("Ping Reply"), pa.pszLabel, 1); } } if(pa.miss_count == -1 - options.retries && options.logging) { TCHAR buf[512]; mir_sntprintf(buf, 512, TranslateT("%s - reply, %d"), pa.pszLabel, pa.round_trip_time); CallService(PLUG "/Log", (WPARAM)buf, 0); } SetProtoStatus(pa.pszLabel, pa.pszProto, pa.get_status, pa.set_status); } else { if(pa.miss_count == 1 + options.retries || ((pa.miss_count % (options.retries + 1)) == 0 && !options.block_reps)) { timeout = true; if(options.show_popup) ShowPopup(TranslateT("Ping Timeout"), pa.pszLabel, 0); } if(pa.miss_count == 1 + options.retries && options.logging) { TCHAR buf[512]; mir_sntprintf(buf, 512, TranslateT("%s - timeout"), pa.pszLabel); CallService(PLUG "/Log", (WPARAM)buf, 0); } } InvalidateRect(list_hwnd, 0, FALSE); } } if(timeout) SkinPlaySound("PingTimeout"); if(reply) SkinPlaySound("PingReply"); if(!get_list_changed()) { upCount = count; total = index; } else { total = 0; } } return 0; } void start_ping_thread() { DWORD tid; if(status_update_thread) CloseHandle(status_update_thread); status_update_thread = CreateThread(0, 0, sttCheckStatusThreadProc, 0, 0, &tid); } void stop_ping_thread() { set_thread_finished(true); SetEvent(hWakeEvent); //ICMP::get_instance()->stop(); WaitForSingleObject(status_update_thread, 2000); TerminateThread(status_update_thread, 0); CloseHandle(status_update_thread); status_update_thread = 0; } bool FrameIsFloating() { if(frame_id == -1) return true; // no frames, always floating return (CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS, MAKEWPARAM(FO_FLOATING, frame_id), 0) != 0); } int FillList(WPARAM wParam, LPARAM lParam) { if(options.logging) CallService(PLUG "/Log", (WPARAM)_T("ping address list reload"), 0); PINGLIST pl; CallService(PLUG "/GetPingList", 0, (LPARAM)&pl); SendMessage(list_hwnd, WM_SETREDRAW, (WPARAM)FALSE, 0); Lock(&data_list_cs, "fill_list"); data_list = pl; SendMessage(list_hwnd, LB_RESETCONTENT, 0, 0); int index = 0; for(pinglist_it j = data_list.begin(); j != data_list.end(); ++j, index++) { SendMessage(list_hwnd, LB_INSERTSTRING, (WPARAM)-1, (LPARAM)&(*j)); } set_list_changed(true); list_size = data_list.size(); Unlock(&data_list_cs); SendMessage(list_hwnd, WM_SETREDRAW, (WPARAM)TRUE, 0); InvalidateRect(list_hwnd, 0, FALSE); SetEvent(hWakeEvent); if(!ServiceExists(MS_CLIST_FRAMES_ADDFRAME) && options.attach_to_clist) UpdateFrame(); return 0; } INT_PTR PingPlugShowWindow(WPARAM wParam, LPARAM lParam) { if(hpwnd) { if (frame_id != -1 && ServiceExists(MS_CLIST_FRAMES_SHFRAME)) CallService(MS_CLIST_FRAMES_SHFRAME, (WPARAM)frame_id, 0); else ShowWindow(hpwnd, IsWindowVisible(hpwnd) ? SW_HIDE : SW_SHOW); } return 0; } #define TIMER_ID 11042 void CALLBACK TimerProc( HWND hwnd, // handle to window UINT uMsg, // WM_TIMER message UINT_PTR idEvent, // timer identifier DWORD dwTime // current system time ) { if(frame_id != -1 && ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) { TCHAR TBcapt[255]; if (total > 0) mir_sntprintf(TBcapt, SIZEOF(TBcapt), _T("Ping (%d/%d)"), upCount, total); else mir_sntprintf(TBcapt, SIZEOF(TBcapt), _T("Ping")); CallService(MS_CLIST_FRAMES_SETFRAMEOPTIONS,MAKEWPARAM(FO_TBNAME | FO_TCHAR,frame_id),(LPARAM)TBcapt); CallService(MS_CLIST_FRAMES_SETFRAMEOPTIONS,MAKEWPARAM(FO_TBTIPNAME | FO_TCHAR,frame_id),(LPARAM)TBcapt); CallService(MS_CLIST_FRAMES_UPDATEFRAME,frame_id,FU_TBREDRAW); } else { // if(options.attach_to_clist) { // AttachToClist(true); // } } } DWORD context_point; bool context_point_valid = false; LRESULT CALLBACK FrameWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { RECT rect; MEASUREITEMSTRUCT *mis; LPDRAWITEMSTRUCT dis; SIZE textSize; PINGADDRESS itemData; RECT r; LPARAM lp; int sel; switch(msg) { case WM_MEASUREITEM: mis = (MEASUREITEMSTRUCT *)lParam; mis->itemWidth = 100; mis->itemHeight = options.row_height; return TRUE; case WM_DRAWITEM: dis = (LPDRAWITEMSTRUCT)lParam; if(dis->hwndItem == list_hwnd) { HBRUSH ttbrush = 0; COLORREF tcol; if(dis->itemID != -1) { Lock(&data_list_cs, "draw item"); itemData = *(PINGADDRESS *)dis->itemData; Unlock(&data_list_cs); SendMessage(list_hwnd, LB_SETITEMHEIGHT, 0, (LPARAM)options.row_height); //dis->rcItem.bottom = dis->rcItem.top + options.row_height; LONG x, y; if(context_point_valid) { RECT r; GetWindowRect(list_hwnd, &r); x = LOWORD(context_point) - r.left, y = HIWORD(context_point) - r.top; } GetClientRect(hwnd, &r); if((dis->itemState & ODS_SELECTED && dis->itemState & ODS_FOCUS) || (context_point_valid && (x >= dis->rcItem.left && x <= dis->rcItem.right) && (y >= dis->rcItem.top && y <= dis->rcItem.bottom))) { tcol = db_get_dw(NULL,"CLC","SelBkColour", GetSysColor(COLOR_HIGHLIGHT)); SetBkColor(dis->hDC, tcol); FillRect(dis->hDC, &dis->rcItem, (ttbrush = CreateSolidBrush(tcol))); tcol = db_get_dw(NULL,"CLC","SelTextColour", GetSysColor(COLOR_HIGHLIGHTTEXT)); SetTextColor(dis->hDC, tcol); } else { tcol = bk_col; SetBkColor(dis->hDC, tcol); FillRect(dis->hDC, &dis->rcItem, (ttbrush = CreateSolidBrush(tcol))); tcol = db_get_dw(NULL, PLUG, "FontCol", GetSysColor(COLOR_WINDOWTEXT)); SetTextColor(dis->hDC, tcol); } SetBkMode(dis->hDC, TRANSPARENT); HICON hIcon = (itemData.status != PS_DISABLED ? (itemData.status == PS_TESTING ? hIconTesting : (itemData.status == PS_RESPONDING ? hIconResponding : hIconNotResponding)) : hIconDisabled); dis->rcItem.left += options.indent; //DrawIconEx(dis->hDC,dis->rcItem.left,(dis->rcItem.top + dis->rcItem.bottom - GetSystemMetrics(SM_CYSMICON))>>1,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL); //DrawIconEx(dis->hDC,dis->rcItem.left,(dis->rcItem.top + dis->rcItem.bottom - GetSystemMetrics(SM_CYSMICON))>>1,hIcon,0, 0, 0, NULL, DI_NORMAL); DrawIconEx(dis->hDC,dis->rcItem.left,dis->rcItem.top + ((options.row_height - 16)>>1),hIcon,0, 0, 0, NULL, DI_NORMAL); GetTextExtentPoint32(dis->hDC,itemData.pszLabel,lstrlen(itemData.pszLabel),&textSize); TextOut(dis->hDC,dis->rcItem.left + 16 + 4,(dis->rcItem.top + dis->rcItem.bottom - textSize.cy)>>1,itemData.pszLabel,lstrlen(itemData.pszLabel)); if(itemData.status != PS_DISABLED) { TCHAR buf[256]; if(itemData.responding) { mir_sntprintf(buf, 256, TranslateT("%d ms"), itemData.round_trip_time); GetTextExtentPoint32(dis->hDC,buf,lstrlen(buf),&textSize); TextOut(dis->hDC,dis->rcItem.right - textSize.cx - 2,(dis->rcItem.top + dis->rcItem.bottom -textSize.cy)>>1,buf,lstrlen(buf)); } else if(itemData.miss_count > 0) { mir_sntprintf(buf, 256, _T("[%d]"), itemData.miss_count); GetTextExtentPoint32(dis->hDC,buf,lstrlen(buf),&textSize); TextOut(dis->hDC,dis->rcItem.right - textSize.cx - 2,(dis->rcItem.top + dis->rcItem.bottom -textSize.cy)>>1,buf,lstrlen(buf)); } } SetBkMode(dis->hDC, OPAQUE); } if(ttbrush) DeleteObject(ttbrush); return TRUE; } //return DefWindowProc(hwnd, msg, wParam, lParam); return TRUE; case WM_CTLCOLORLISTBOX: { if(tbrush) DeleteObject(tbrush); return (BOOL)(tbrush = CreateSolidBrush(bk_col)); } case WM_ERASEBKGND: { RECT r; GetClientRect(hwnd, &r); if(!tbrush) tbrush = CreateSolidBrush(bk_col); FillRect((HDC)wParam, &r, tbrush); } return TRUE; case WM_CONTEXTMENU: { context_point = lParam; context_point_valid = true; InvalidateRect(list_hwnd, 0, FALSE); HMENU menu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_MENU1)), submenu = GetSubMenu(menu, 0); POINT pt = {LOWORD(context_point),HIWORD(context_point)}; RECT r; GetClientRect(list_hwnd, &r); ScreenToClient(list_hwnd, &pt); DWORD item = SendMessage(list_hwnd, LB_ITEMFROMPOINT, 0, MAKELPARAM(pt.x, pt.y)); bool found = false; if(HIWORD(item) == 0) { int count = LOWORD(item); Lock(&data_list_cs, "show graph"); if(count >= 0 && count < (int)data_list.size()) { itemData = *(PINGADDRESS *)SendMessage(list_hwnd, LB_GETITEMDATA, count, 0); found = true; } Unlock(&data_list_cs); } if(found) { EnableMenuItem(submenu, ID_MENU_GRAPH, MF_BYCOMMAND | MF_ENABLED); EnableMenuItem(submenu, ID_MENU_EDIT, MF_BYCOMMAND | MF_ENABLED); EnableMenuItem(submenu, ID_MENU_TOGGLE, MF_BYCOMMAND | MF_ENABLED); if(itemData.status == PS_DISABLED) { ModifyMenu(submenu, ID_MENU_TOGGLE, MF_BYCOMMAND | MF_STRING, ID_MENU_TOGGLE, TranslateT("Enable")); } else { ModifyMenu(submenu, ID_MENU_TOGGLE, MF_BYCOMMAND | MF_STRING, ID_MENU_TOGGLE, TranslateT("Disable")); } } else { EnableMenuItem(submenu, ID_MENU_GRAPH, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(submenu, ID_MENU_EDIT, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(submenu, ID_MENU_TOGGLE, MF_BYCOMMAND | MF_GRAYED); } TranslateMenu(submenu); //ClientToScreen(list_hwnd, &pt); GetCursorPos(&pt); BOOL ret = TrackPopupMenu(submenu, TPM_TOPALIGN|TPM_LEFTALIGN|TPM_RIGHTBUTTON|TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, NULL); DestroyMenu(menu); if(ret) { SendMessage(hwnd, WM_COMMAND, ret, 0); } context_point_valid = false; InvalidateRect(list_hwnd, 0, FALSE); } return TRUE; case WM_SYSCOLORCHANGE: SendMessage(list_hwnd,msg,wParam,lParam); return DefWindowProc(hwnd, msg, wParam, lParam); case WM_CREATE: list_hwnd = CreateWindow(_T("LISTBOX"), _T(""), //(WS_VISIBLE | WS_CHILD | LBS_NOINTEGRALHEIGHT| LBS_STANDARD | WS_CLIPCHILDREN | LBS_OWNERDRAWVARIABLE | LBS_NOTIFY) (WS_VISIBLE | WS_CHILD | LBS_STANDARD | LBS_OWNERDRAWFIXED | LBS_NOTIFY) & ~WS_BORDER, 0, 0, 0, 0, hwnd, NULL, hInst,0); if (db_get_b(NULL,"CList","Transparent",0)) { if(ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) { } else { #ifdef WS_EX_LAYERED SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED); #endif #ifdef LWA_ALPHA SetLayeredWindowAttributes(hwnd, RGB(0,0,0), (BYTE)db_get_b(NULL,"CList","Alpha",SETTING_ALPHA_DEFAULT), LWA_ALPHA); #endif } } // timer to update titlebar if(ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) SetTimer(hwnd, TIMER_ID, 1000, TimerProc); PostMessage(hwnd, WM_SIZE, 0, 0); return TRUE; case WM_ACTIVATE: if(wParam==WA_INACTIVE) { if((HWND)wParam!=hwnd) if(db_get_b(NULL,"CList","Transparent",SETTING_TRANSPARENT_DEFAULT)) if(transparentFocus) SetTimer(hwnd, TM_AUTOALPHA,250,NULL); } else { if(db_get_b(NULL,"CList","Transparent",SETTING_TRANSPARENT_DEFAULT)) { KillTimer(hwnd,TM_AUTOALPHA); #ifdef LWA_ALPHA SetLayeredWindowAttributes(hwnd, RGB(0,0,0), (BYTE)db_get_b(NULL,"CList","Alpha",SETTING_ALPHA_DEFAULT), LWA_ALPHA); #endif transparentFocus=1; } } return DefWindowProc(hwnd,msg,wParam,lParam); case WM_SETCURSOR: if(db_get_b(NULL,"CList","Transparent",SETTING_TRANSPARENT_DEFAULT)) { if (!transparentFocus && GetForegroundWindow()!=hwnd) { #ifdef LWA_ALPHA SetLayeredWindowAttributes(hwnd, RGB(0,0,0), (BYTE)db_get_b(NULL,"CList","Alpha",SETTING_ALPHA_DEFAULT), LWA_ALPHA); #endif transparentFocus=1; SetTimer(hwnd, TM_AUTOALPHA,250,NULL); } } return DefWindowProc(hwnd,msg,wParam,lParam); case WM_TIMER: if ((int)wParam==TM_AUTOALPHA) { int inwnd; if (GetForegroundWindow()==hwnd) { KillTimer(hwnd,TM_AUTOALPHA); inwnd=1; } else { POINT pt; HWND hwndPt; pt.x=(short)LOWORD(GetMessagePos()); pt.y=(short)HIWORD(GetMessagePos()); hwndPt=WindowFromPoint(pt); inwnd=(hwndPt==hwnd || GetParent(hwndPt)==hwnd); } if (inwnd!=transparentFocus) { //change transparentFocus=inwnd; #ifdef LWA_ALPHA if(transparentFocus) SetLayeredWindowAttributes(hwnd, RGB(0,0,0), (BYTE)db_get_b(NULL,"CList","Alpha",SETTING_ALPHA_DEFAULT), LWA_ALPHA); else SetLayeredWindowAttributes(hwnd, RGB(0,0,0), (BYTE)db_get_b(NULL,"CList","AutoAlpha",SETTING_AUTOALPHA_DEFAULT), LWA_ALPHA); #endif } if(!transparentFocus) KillTimer(hwnd,TM_AUTOALPHA); return TRUE; } return FALSE; case WM_SHOWWINDOW: { static int noRecurse=0; if(lParam) break; if(noRecurse) break; if(!db_get_b(NULL,"CLUI","FadeInOut",0)) break; #ifdef WS_EX_LAYERED if(GetWindowLong(hwnd,GWL_EXSTYLE)&WS_EX_LAYERED) { DWORD thisTick,startTick; int sourceAlpha,destAlpha; if(wParam) { sourceAlpha=0; destAlpha=(BYTE)db_get_b(NULL,"CList","Alpha",SETTING_AUTOALPHA_DEFAULT); #ifdef LWA_ALPHA SetLayeredWindowAttributes(hwnd, RGB(0,0,0), 0, LWA_ALPHA); #endif noRecurse=1; ShowWindow(hwnd,SW_SHOW); noRecurse=0; } else { sourceAlpha=(BYTE)db_get_b(NULL,"CList","Alpha",SETTING_AUTOALPHA_DEFAULT); destAlpha=0; } for(startTick=GetTickCount();;) { thisTick=GetTickCount(); if(thisTick>=startTick+200) break; #ifdef LWA_ALPHA SetLayeredWindowAttributes(hwnd, RGB(0,0,0), (BYTE)(sourceAlpha+(destAlpha-sourceAlpha)*(int)(thisTick-startTick)/200), LWA_ALPHA); #endif } #ifdef LWA_ALPHA SetLayeredWindowAttributes(hwnd, RGB(0,0,0), (BYTE)destAlpha, LWA_ALPHA); #endif } else { // if(wParam) SetForegroundWindow(hwnd); AnimateWindow(hwnd,200,AW_BLEND|(wParam?0:AW_HIDE)); //SetWindowPos(label,0,0,0,0,0,SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_FRAMECHANGED); } #endif //int res = DefWindowProc(hwnd, msg, wParam, lParam); //return res; //break; //return FALSE; //break; return DefWindowProc(hwnd, msg, wParam, lParam); } /* case WM_PAINT: { paintDC = BeginPaint(hwnd, &paintStruct); // //SelectObject(paintDC,TitleBarFont); //SetBkMode(paintDC,TRANSPARENT); //paintStruct.fErase=TRUE; //color=RGB(1,1,1); //brush=CreateSolidBrush(RGB(200,20,20)); //GetClientRect(hwnd,&rect); //FillRect(paintDC,&rect,brush); //TextOut(paintDC,4,4,"cl1 Bottom window",sizeof("cl1 Bottom window")-1); //DeleteObject(brush); EndPaint(hwnd, &paintStruct); // }; return TRUE; */ case WM_COMMAND: //CreateServiceFunction("PingPlug/DisableAll", PingPlugDisableAll); //CreateServiceFunction("PingPlug/EnableAll", PingPlugEnableAll); switch(LOWORD(wParam)) { case ID_MENU_GRAPH: if(context_point_valid) { WORD x = LOWORD(context_point), y = HIWORD(context_point); RECT r; GetWindowRect(list_hwnd, &r); DWORD item = SendMessage(list_hwnd, LB_ITEMFROMPOINT, 0, MAKELPARAM(x - r.left, y - r.top)); if(HIWORD(item) == 0) { int count = LOWORD(item); bool found = false; Lock(&data_list_cs, "menu show graph"); if(count >= 0 && count < (int)data_list.size()) { itemData = *(PINGADDRESS *)SendMessage(list_hwnd, LB_GETITEMDATA, count, 0); found = true; } Unlock(&data_list_cs); if(found) CallService(PLUG "/ShowGraph", (WPARAM)itemData.item_id, (LPARAM)itemData.pszLabel); } } return TRUE; case ID_MENU_TOGGLE: if(context_point_valid) { WORD x = LOWORD(context_point), y = HIWORD(context_point); RECT r; GetWindowRect(list_hwnd, &r); DWORD item = SendMessage(list_hwnd, LB_ITEMFROMPOINT, 0, MAKELPARAM(x - r.left, y - r.top)); if(HIWORD(item) == 0) { int count = LOWORD(item); bool found = false; Lock(&data_list_cs, "menu toggle"); if(count >= 0 && count < (int)data_list.size()) { itemData = *(PINGADDRESS *)SendMessage(list_hwnd, LB_GETITEMDATA, count, 0); found = true; } Unlock(&data_list_cs); if(found) CallService(PLUG "/ToggleEnabled", (WPARAM)itemData.item_id, 0); } } return TRUE; case ID_MENU_EDIT: if(context_point_valid) { WORD x = LOWORD(context_point), y = HIWORD(context_point); RECT r; GetWindowRect(list_hwnd, &r); DWORD item = SendMessage(list_hwnd, LB_ITEMFROMPOINT, 0, MAKELPARAM(x - r.left, y - r.top)); PINGADDRESS *temp = 0; if(HIWORD(item) == 0) { int count = LOWORD(item); Lock(&data_list_cs, "menu edit"); if(count >= 0 && count < (int)data_list.size()) { temp = (PINGADDRESS *)SendMessage(list_hwnd, LB_GETITEMDATA, count, 0); } Unlock(&data_list_cs); if(temp) { itemData = *temp; if(Edit(hwnd, itemData)) { Lock(&data_list_cs, "menu edited"); *temp = itemData; CallService(PLUG "/SetAndSavePingList", (WPARAM)&data_list, 0); Unlock(&data_list_cs); } } } } return TRUE; case ID_MENU_DISABLEALLPINGS: CallService(PLUG "/DisableAll", 0, 0); return TRUE; case ID_MENU_ENABLEALLPINGS: CallService(PLUG "/EnableAll", 0, 0); return TRUE; case ID_MENU_OPTIONS: { OPENOPTIONSDIALOG oop = {0}; oop.cbSize = sizeof(oop); oop.pszGroup = "Network"; oop.pszPage = "PING"; oop.pszTab = "Settings"; Options_Open(&oop); } return TRUE; case ID_MENU_DESTINATIONS: { OPENOPTIONSDIALOG oop = {0}; oop.cbSize = sizeof(oop); oop.pszGroup = "Network"; oop.pszPage = "PING"; oop.pszTab = "Hosts"; Options_Open(&oop); } return TRUE; } if (HIWORD( wParam ) == LBN_DBLCLK) { sel = SendMessage(list_hwnd, LB_GETCURSEL, 0, 0); if(sel != LB_ERR) { lp = SendMessage(list_hwnd, LB_GETITEMDATA, sel, 0); if(lp != LB_ERR) { PINGADDRESS *pItemData = (PINGADDRESS *)lp; Lock(&data_list_cs, "command"); if(pItemData) { DWORD item_id = pItemData->item_id; Unlock(&data_list_cs); int wake = CallService(PLUG "/DblClick", (WPARAM)item_id, 0); InvalidateRect(list_hwnd, 0, FALSE); if(wake) SetEvent(hWakeEvent); if(options.logging) { TCHAR buf[1024]; mir_sntprintf(buf, 1024, _T("%s - %s"), pItemData->pszLabel, (wake ? TranslateT("enabled") : TranslateT("double clicked"))); CallService(PLUG "/Log", (WPARAM)buf, 0); } } else { Unlock(&data_list_cs); } } } return TRUE; } return DefWindowProc(hwnd, msg, wParam, lParam); case WM_MOVE: // needed for docked frames in clist_mw (not needed in clist_modern) if(FrameIsFloating()) break; case WM_SIZE: { //PostMessage(label, WM_SIZE, wParam, lParam); GetClientRect(hwnd,&rect); //SetWindowPos(list_hwnd, 0, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, SWP_NOZORDER); //InvalidateRect(list_hwnd, &rect, FALSE); int winheight = rect.bottom - rect.top, itemheight = SendMessage(list_hwnd, LB_GETITEMHEIGHT, 0, 0), count = SendMessage(list_hwnd, LB_GETCOUNT, 0, 0), #ifdef min height = min(winheight - winheight % itemheight, itemheight * count); #else height = std::min(winheight - winheight % itemheight, itemheight * count); #endif SetWindowPos(list_hwnd, 0, rect.left, rect.top, rect.right-rect.left, height, SWP_NOZORDER); InvalidateRect(list_hwnd, 0, FALSE); } InvalidateRect(hwnd, 0, TRUE); return DefWindowProc(hwnd, msg, wParam, lParam); case WM_DESTROY: if(!ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) { Utils_SaveWindowPosition(hwnd, 0, PLUG, "main_window"); } KillTimer(hwnd, TIMER_ID); if(tbrush) DeleteObject(tbrush); DestroyWindow(list_hwnd); return DefWindowProc(hwnd, msg, wParam, lParam); case WM_CLOSE: if(!ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) { Utils_SaveWindowPosition(hwnd, 0, PLUG, "main_window"); ShowWindow(hwnd, SW_HIDE); return 0; } return DefWindowProc(hwnd, msg, wParam, lParam); /* case WM_POWERBROADCAST: if(options.logging) { std::ostringstream oss; switch(wParam) { case PBT_APMSUSPEND: CallService("PingPlug/Log", (WPARAM)"system suspend", 0); break; case PBT_APMRESUMESUSPEND: oss << "system resume"; if(lParam == PBTF_APMRESUMEFROMFAILURE) oss << " [suspend failure!]"; CallService("PingPlug/Log", (WPARAM)oss.str().c_str(), 0); break; case PBT_APMRESUMEAUTOMATIC: oss << "system resume (automatic)"; if(lParam == PBTF_APMRESUMEFROMFAILURE) oss << " [suspend failure!]"; CallService("PingPlug/Log", (WPARAM)oss.str().c_str(), 0); break; case PBT_APMRESUMECRITICAL: oss << "system resume (critical)"; if(lParam == PBTF_APMRESUMEFROMFAILURE) oss << " [suspend failure!]"; CallService("PingPlug/Log", (WPARAM)oss.str().c_str(), 0); break; } } break; */ default: return DefWindowProc(hwnd, msg, wParam, lParam); }; return(TRUE); }; int ReloadFont(WPARAM, LPARAM) { if(hFont) DeleteObject(hFont); LOGFONT log_font; CallService(MS_FONT_GETT, (WPARAM)&font_id, (LPARAM)&log_font); hFont = CreateFontIndirect(&log_font); SendMessage(list_hwnd, WM_SETFONT, (WPARAM)hFont, (LPARAM)TRUE); bk_col = CallService(MS_COLOUR_GETT, (WPARAM)&bk_col_id, 0); RefreshWindow(0, 0); return 0; } int RefreshWindow(WPARAM, LPARAM) { InvalidateRect(list_hwnd, 0, TRUE); InvalidateRect(hpwnd, 0, TRUE); return 0; } void UpdateFrame() { if(IsWindowVisible(hwnd_clist) != IsWindowVisible(hpwnd)) ShowWindow(hpwnd, IsWindowVisible(hwnd_clist) ? SW_SHOW : SW_HIDE); if(!IsWindowVisible(hpwnd)) return; RECT r_clist; GetWindowRect(hwnd_clist, &r_clist); RECT r_frame; GetWindowRect(hpwnd, &r_frame); int height = (int)list_size * options.row_height; if(GetWindowLong(hpwnd, GWL_STYLE) & WS_BORDER) { RECT r_frame_client; GetClientRect(hpwnd, &r_frame_client); height += (r_frame.bottom - r_frame.top) - (r_frame_client.bottom - r_frame_client.top); } SetWindowPos(hpwnd, 0, r_clist.left, r_clist.top - height, (r_clist.right - r_clist.left), height, SWP_NOZORDER | SWP_NOACTIVATE); } // Subclass procedure LRESULT APIENTRY ClistSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if(uMsg == WM_SIZE || uMsg == WM_MOVE) UpdateFrame(); if(uMsg == WM_NCCALCSIZE) { // possible window style change if(GetWindowLong(hwnd_clist, GWL_STYLE) != GetWindowLong(hpwnd, GWL_STYLE) || GetWindowLong(hwnd_clist, GWL_STYLE) != GetWindowLong(hpwnd, GWL_STYLE)) { SetWindowLong(hpwnd, GWL_STYLE, GetWindowLong(hwnd_clist, GWL_STYLE)); SetWindowLong(hpwnd, GWL_EXSTYLE, GetWindowLong(hwnd_clist, GWL_EXSTYLE)); SetWindowPos(hpwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE); } } if(uMsg == WM_SHOWWINDOW) ShowWindow(hpwnd, wParam); return mir_callNextSubclass(hwnd, ClistSubclassProc, uMsg, wParam, lParam); } void AttachToClist(bool attach) { if(!hpwnd) return; if(attach) { SetWindowLong(hpwnd, GWL_STYLE, GetWindowLong(hwnd_clist, GWL_STYLE)); SetWindowLong(hpwnd, GWL_EXSTYLE, GetWindowLong(hwnd_clist, GWL_EXSTYLE)); SetWindowPos(hpwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE); // subclass clist to trap move/size mir_subclassWindow(hwnd_clist, ClistSubclassProc); UpdateFrame(); } else { SetWindowLong(hpwnd, GWL_STYLE, (WS_POPUPWINDOW | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_VISIBLE | WS_CLIPCHILDREN)); SetWindowLong(hpwnd, GWL_EXSTYLE, WS_EX_TOOLWINDOW); SetWindowPos(hpwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE); } } void InitList() { hwnd_clist = (HWND)CallService(MS_CLUI_GETHWND, 0, 0); WNDCLASS wndclass; wndclass.style = 0; wndclass.lpfnWndProc = FrameWindowProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInst; wndclass.hIcon = hIconResponding; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)(COLOR_3DFACE+1); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = _T(PLUG) _T("WindowClass"); RegisterClass(&wndclass); if(ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) { hpwnd=CreateWindow(_T(PLUG) _T("WindowClass"), _T("Ping"), (WS_BORDER | WS_CHILD | WS_CLIPCHILDREN), 0, 0, 0, 0, hwnd_clist, NULL, hInst, NULL); CLISTFrame frame = {0}; frame.name=PLUG; frame.cbSize=sizeof(CLISTFrame); frame.hWnd=hpwnd; frame.align=alBottom; frame.Flags=F_VISIBLE | F_SHOWTB | F_SHOWTBTIP; frame.height=30; frame.TBname=Translate("Ping"); frame_id=CallService(MS_CLIST_FRAMES_ADDFRAME,(WPARAM)&frame,0); } else { hpwnd=CreateWindowEx(WS_EX_TOOLWINDOW, _T(PLUG) _T("WindowClass"),_T("Ping"), (WS_POPUPWINDOW | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_CLIPCHILDREN), 0,0,400,300,hwnd_clist,NULL,hInst,NULL); Utils_RestoreWindowPosition(hpwnd, 0, PLUG, "main_window"); CreateServiceFunction(PLUG "/ShowWindow", PingPlugShowWindow); CLISTMENUITEM mi = { sizeof(mi) }; mi.flags = CMIF_TCHAR; mi.popupPosition = 1000200001; mi.ptszPopupName = LPGENT("Ping"); mi.position = 3000320001; mi.hIcon = 0;//LoadIcon( hInst, 0); mi.ptszName = LPGENT( "Show/Hide &Ping Window" ); mi.pszService = PLUG "/ShowWindow"; Menu_AddMainMenuItem(&mi); if(options.attach_to_clist) AttachToClist(true); else ShowWindow(hpwnd, SW_SHOW); } { font_id.cbSize = sizeof(FontIDT); _tcsncpy(font_id.group, LPGENT("Ping"), SIZEOF(font_id.group)); _tcsncpy(font_id.name, LPGENT("List"), SIZEOF(font_id.name)); strncpy(font_id.dbSettingsGroup, "PING", sizeof(font_id.dbSettingsGroup)); strncpy(font_id.prefix, "Font", sizeof(font_id.prefix)); _tcsncpy(font_id.backgroundGroup, _T("Ping"), SIZEOF(font_id.backgroundGroup)); _tcsncpy(font_id.backgroundName, _T("Background"), SIZEOF(font_id.backgroundName)); font_id.order = 0; font_id.flags = FIDF_DEFAULTVALID; font_id.deffontsettings.charset = DEFAULT_CHARSET; font_id.deffontsettings.size = -14; font_id.deffontsettings.style = 0; font_id.deffontsettings.colour = RGB(255, 255, 255); _tcsncpy(font_id.deffontsettings.szFace, _T("Tahoma"), SIZEOF(font_id.deffontsettings.szFace)); FontRegisterT(&font_id); bk_col_id.cbSize = sizeof(ColourIDT); _tcsncpy(bk_col_id.group, _T("Ping"), SIZEOF(bk_col_id.group)); _tcsncpy(bk_col_id.name, _T("Background"), SIZEOF(bk_col_id.name)); strncpy(bk_col_id.dbSettingsGroup, "PING", sizeof(bk_col_id.dbSettingsGroup)); strncpy(bk_col_id.setting, "BgColor", sizeof(bk_col_id.setting)); bk_col_id.defcolour = RGB(0,0,0); ColourRegisterT(&bk_col_id); HookEvent(ME_FONT_RELOAD, ReloadFont); ReloadFont(0, 0); } start_ping_thread(); } void DeinitList() { DestroyWindow(hpwnd); stop_ping_thread(); if(hFont) DeleteObject(hFont); }