#include #include #include #include #include #include "session_notification.h" #include "pport.h" #include "resources.h" #include "parseCmdLine.h" #include "pppc.h" using namespace std; #define SET_BIT(var,position,value) \ (var) = ((var) & (~(1 << (position)))) | ((value) << (position)) #define GET_BIT(var,position) \ (((var) >> (position)) & 0x1) static LRESULT WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); const char * PPPC::ConfigEntryCaptions[3] = {"Auto", "Manual: Off", "Manual: On"}; static HMENU g_popupMenu; int WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { /* parse command line into an array like sane operating systems supply */ vector args = parseCmdLine(lpCmdLine); const char * config_file = NULL; /* process command line arguments */ for (int sz = args.size(), i = 0; i < sz; i++) { if (args[i][0] != '-') { config_file = args[i].c_str(); } } if (config_file == NULL) { config_file = "pppc.ini"; } PPPC myPPPC(hInstance, config_file); return myPPPC.mainLoop(); } static LRESULT WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_NCCREATE: return 1; case WM_CREATE: break; case WM_CLOSE: ::DestroyWindow(hWnd); break; case WM_DESTROY: ::PostQuitMessage(0); break; case WM_ICON_NOTIFY: if (wParam == 0) { if (LOWORD(lParam) == WM_RBUTTONUP) { POINT pos; GetCursorPos(&pos); ::SetForegroundWindow(hWnd); ::TrackPopupMenu(g_popupMenu, 0, pos.x, pos.y, 0, hWnd, NULL); // BUGFIX: See "PRB: Menus for Notification Icons Don't Work Correctly" ::PostMessage(hWnd, WM_NULL, 0, 0); } } break; } return 0; } void addMenuItem(HMENU hMenu, const CHAR * itemstr, WORD id) { MENUITEMINFO mii; memset(&mii, 0, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_STRING | MIIM_ID; mii.wID = id; mii.dwTypeData = (CHAR *) itemstr; mii.cch = strlen(mii.dwTypeData); if (::InsertMenuItem(hMenu, 0, TRUE, &mii) == 0) { cerr << "Warning: InsertMenuItem(): " << GetLastError() << endl; } } HMENU addMenuSubMenu(HMENU hMenu, const CHAR * itemstr, WORD id) { HMENU submenu = ::CreatePopupMenu(); MENUITEMINFO mii; memset(&mii, 0, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_STRING | MIIM_SUBMENU | MIIM_ID; mii.wID = id; mii.dwTypeData = (CHAR *) itemstr; mii.cch = strlen(mii.dwTypeData); mii.hSubMenu = submenu; if (::InsertMenuItem(hMenu, 0, TRUE, &mii) == 0) { cerr << "Warning: InsertMenuItem(): " << GetLastError() << endl; } return submenu; } void updateMenuInfo(HMENU hMenu, int index, const CHAR * itemstr, WORD id, bool checked) { MENUITEMINFO mii; memset(&mii, 0, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_STRING | MIIM_ID | MIIM_STATE; mii.fState = checked ? MFS_CHECKED : 0; mii.wID = id; mii.dwTypeData = (CHAR *) itemstr; mii.cch = strlen(mii.dwTypeData); if (::SetMenuItemInfo(hMenu, index, TRUE, &mii) == 0) { cerr << "Warning: InsertMenuItem(): " << GetLastError() << endl; } } PPPC::PPPC(HINSTANCE hInstance, const char * config_file) { m_pins = 0u; if (config_file != NULL) { m_config.read(config_file); } /* Load the application icon */ HICON icon = ::LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1)); if (icon == 0) { cerr << "Warning: LoadIcon(): " << GetLastError() << endl; } /* Create the TrayIconClass class */ WNDCLASSEX wcex; memset(&wcex, 0, sizeof(wcex)); wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wcex.lpfnWndProc = (WNDPROC)WindowProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = icon; wcex.hCursor = 0; wcex.hbrBackground = 0; wcex.lpszMenuName = 0; wcex.lpszClassName = "TrayIconClass"; wcex.hIconSm = 0; RegisterClassEx(&wcex); /* Create the tray icon window */ m_hWnd = ::CreateWindow("TrayIconClass", "", WS_POPUP, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, NULL, 0, hInstance, 0); if (m_hWnd == NULL) { cerr << "Warning: CreateWindow(): " << GetLastError() << endl; } /* Create the right-click icon context menu */ m_popupMenu = ::CreatePopupMenu(); g_popupMenu = m_popupMenu; addMenuItem(m_popupMenu, "E&xit", 0); for (int sz = m_config.num_entries(), i = 0; i < sz; i++) { int config_id = i + 1; HMENU submenu = addMenuSubMenu(m_popupMenu, m_config.entries[i].name.c_str(), (config_id << 8)); m_menus.push_back(submenu); m_modes.push_back(AUTO); for (int j = 0; j < 3; j++) { addMenuItem(submenu, ConfigEntryCaptions[i], (config_id << 8) | (j + 1)); } updateConfigMenus(i); } /* Create the notify icon data */ memset(&m_nid, 0, sizeof(m_nid)); m_nid.cbSize = sizeof(NOTIFYICONDATA); m_nid.hWnd = m_hWnd; m_nid.uID = 0; m_nid.hIcon = icon; m_nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; m_nid.uCallbackMessage = WM_ICON_NOTIFY; strncpy(m_nid.szTip, APP_NAME, sizeof(m_nid.szTip)); BOOL bResult = Shell_NotifyIcon(NIM_ADD, &m_nid); if (bResult == 0) { cerr << "Warning: Shell_NotifyIcon(): " << GetLastError() << endl; } event_start(); /* begin capturing session notifications */ session_notification_enable(m_hWnd); } void PPPC::updateConfigMenus(int i) { for (int index = 0; index < 3; index++) { updateMenuInfo(m_menus[i], index, ConfigEntryCaptions[index], (((i + 1) << 8) | (index + 1)), index == m_modes[i]); } } BOOL PPPC::mainLoop() { BOOL bRet; MSG msg; bool running = true; while(running) { bRet = GetMessage(&msg, NULL, 0, 0); if (bRet == -1 || bRet == 0) { break; } switch (msg.message) { case WM_PAINT: break; case WM_CLOSE: case WM_DESTROY: case WM_QUIT: running = false; break; case WM_WTSSESSION_CHANGE: if (msg.wParam == WTS_SESSION_LOGON || msg.wParam == WTS_SESSION_UNLOCK) { event_unlock(); } if (msg.wParam == WTS_SESSION_LOGOFF || msg.wParam == WTS_SESSION_LOCK) { event_lock(); } break; case WM_COMMAND: { int menu_index = LOWORD(msg.wParam); if (menu_index == 0) { running = false; } else { int config_index = ((menu_index >> 8) & 0xFF) - 1; int mode_index = ((menu_index) & 0xFF) - 1; m_modes[config_index] = (ConfigEntryMode) mode_index; updateConfigMenus(config_index); update_pins(); } } break; } } return bRet; } PPPC::~PPPC() { ::DestroyMenu(m_popupMenu); event_exit(); /* delete the tray icon */ Shell_NotifyIcon(NIM_DELETE, &m_nid); /* stop listening for session notifications */ session_notification_disable(m_hWnd); } void PPPC::event_start() { for (int sz = m_config.num_entries(), i = 0; i < sz; i++) { if (m_modes[i] == AUTO) { switch (m_config.entries[i].on_start) { case Config::ON: SET_BIT(m_pins, m_config.entries[i].pin, 1); break; case Config::OFF: SET_BIT(m_pins, m_config.entries[i].pin, 0); break; default: break; } } } update_pins(); } void PPPC::event_exit() { for (int sz = m_config.num_entries(), i = 0; i < sz; i++) { if (m_modes[i] == AUTO) { switch (m_config.entries[i].on_exit) { case Config::ON: SET_BIT(m_pins, m_config.entries[i].pin, 1); break; case Config::OFF: SET_BIT(m_pins, m_config.entries[i].pin, 0); break; default: break; } } } update_pins(); } void PPPC::event_lock() { for (int sz = m_config.num_entries(), i = 0; i < sz; i++) { if (m_modes[i] == AUTO) { switch (m_config.entries[i].on_lock) { case Config::ON: SET_BIT(m_pins, m_config.entries[i].pin, 1); break; case Config::OFF: SET_BIT(m_pins, m_config.entries[i].pin, 0); break; default: break; } } } m_previous_pins = m_pins; update_pins(); } void PPPC::event_unlock() { for (int sz = m_config.num_entries(), i = 0; i < sz; i++) { if (m_modes[i] == AUTO) { switch (m_config.entries[i].on_unlock) { case Config::ON: SET_BIT(m_pins, m_config.entries[i].pin, 1); break; case Config::OFF: SET_BIT(m_pins, m_config.entries[i].pin, 0); break; case Config::PREVIOUS: SET_BIT(m_pins, m_config.entries[i].pin, GET_BIT(m_previous_pins, m_config.entries[i].pin)); break; default: break; } } } update_pins(); } void PPPC::update_pins() { for (int sz = m_config.num_entries(), i = 0; i < sz; i++) { if (m_modes[i] == MANUAL_OFF) SET_BIT(m_pins, m_config.entries[i].pin, 0); else if (m_modes[i] == MANUAL_ON) SET_BIT(m_pins, m_config.entries[i].pin, 1); } pport_write(m_pins); }