diff options
Diffstat (limited to 'utils/vproject/vproject.cpp')
| -rw-r--r-- | utils/vproject/vproject.cpp | 648 |
1 files changed, 648 insertions, 0 deletions
diff --git a/utils/vproject/vproject.cpp b/utils/vproject/vproject.cpp new file mode 100644 index 0000000..36be00c --- /dev/null +++ b/utils/vproject/vproject.cpp @@ -0,0 +1,648 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// VPROJECT.CPP +// +//=====================================================================================// +#include "vproject.h" + +#define MAX_PROJECTS 50 + +#define ID_PROJECTS_LISTVIEW 100 + +// column id +#define ID_PROJECT_NAME 0 +#define ID_PROJECT_DIRECTORY 1 + +#define WM_TRAY (WM_APP + 1) +#define ID_TRAY 5000 +#define ID_TRAY_ADDVPROJECT 6000 +#define ID_TRAY_MODIFYVPROJECT 6001 +#define ID_TRAY_MOVEUP 6002 +#define ID_TRAY_MOVEDOWN 6003 +#define ID_TRAY_EXIT 6004 + +typedef struct +{ + char *pName; + char *pGamedir; +} project_t; + +HWND g_hWnd; +char g_project_name[256]; +char g_project_gamedir[256]; +HINSTANCE g_hInstance; +project_t g_projects[MAX_PROJECTS]; +int g_numProjects; +NOTIFYICONDATA g_iconData; +HMENU g_hMenu; +int g_nActiveVProject; +POINT g_cursorPoint; + +void TrayMessageHandler( HWND hWnd, UINT uMessageID ); + +//----------------------------------------------------------------------------- +// SetVProject +// +//----------------------------------------------------------------------------- +void SetVProject( const char *pProjectName ) +{ + char *pGamedir; + char project[256]; + int i; + + if ( pProjectName ) + { + strcpy( project, pProjectName ); + Sys_StripQuotesFromToken( project ); + + for ( i=0; i<g_numProjects; i++ ) + { + if ( !stricmp( g_projects[i].pName, project ) ) + { + // found + break; + } + } + + if ( i >= g_numProjects ) + { + // not found + return; + } + + pGamedir = g_projects[i].pGamedir; + } + else + { + pGamedir = ""; + } + + // Changed to CURRENT_USER to solve security issues in vista! + Sys_SetRegistryString( + //"HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\Environment\\VProject", + "HKEY_CURRENT_USER\\Environment\\VProject" + pGamedir ); + + DWORD result; + SendMessageTimeout( + HWND_BROADCAST, + WM_SETTINGCHANGE, + 0, + (LPARAM)"Environment", + SMTO_ABORTIFHUNG, + 0, + &result ); +} + +//----------------------------------------------------------------------------- +// ModifyVProject +// +//----------------------------------------------------------------------------- +void ModifyVProject( int index, const char *pName, const char *pGamedir ) +{ + free( g_projects[index].pName ); + free( g_projects[index].pGamedir ); + + if ( !pName || !pName[0] ) + { + // delete + if ( g_numProjects-index-1 > 0 ) + { + // shift remaining elements + memcpy( &g_projects[index], &g_projects[index+1], (g_numProjects-index-1)*sizeof( project_t ) ); + } + + g_projects[g_numProjects-1].pName = NULL; + g_projects[g_numProjects-1].pGamedir = NULL; + + g_numProjects--; + + if ( g_nActiveVProject == index+1 ) + { + // deleted current vproject + if ( !g_numProjects ) + { + // no more projects + g_nActiveVProject = 0; + SetVProject( NULL ); + } + else + { + // set to top + g_nActiveVProject = 1; + SetVProject( g_projects[0].pName ); + } + } + } + else + { + g_projects[index].pName = strdup( pName ); + g_projects[index].pGamedir = strdup( pGamedir ); + } +} + +//----------------------------------------------------------------------------- +// AddVProject +// +//----------------------------------------------------------------------------- +void AddVProject( const char *pName, const char *pGamedir ) +{ + if ( !pName || !pName[0] ) + { + // do not add empty projects + return; + } + + ModifyVProject( g_numProjects, pName, pGamedir ); + g_numProjects++; +} + +//----------------------------------------------------------------------------- +// LoadRegistryValues +// +//----------------------------------------------------------------------------- +void LoadRegistryValues() +{ + char keyBuff[32]; + char valueBuff[256]; + char projectName[256]; + char gamedirString[256]; + char *ptr; + char *token; + int i; + + for ( i=0; i<MAX_PROJECTS; i++ ) + { + projectName[0] = '\0'; + gamedirString[0] = '\0'; + + sprintf( keyBuff, "project%d", i ); + Sys_GetRegistryString( keyBuff, valueBuff, "", sizeof( valueBuff ) ); + + // parse and populate valid values + ptr = valueBuff; + token = Sys_GetToken( &ptr, false, NULL ); + if ( token[0] ) + { + strcpy( projectName, token ); + } + else + { + continue; + } + + token = Sys_GetToken( &ptr, false, NULL ); + if ( token[0] ) + { + strcpy( gamedirString, token ); + } + + AddVProject( projectName, gamedirString ); + } +} + +//----------------------------------------------------------------------------- +// SaveRegistryValues +// +//----------------------------------------------------------------------------- +void SaveRegistryValues() +{ + char valueBuff[256]; + char keyBuff[32]; + char *pProjectName; + char *pGamedir; + int len; + int i; + + for ( i=0; i<MAX_PROJECTS; i++ ) + { + sprintf( keyBuff, "project%d", i ); + + pProjectName = g_projects[i].pName; + if ( !pProjectName ) + { + pProjectName = ""; + } + + pGamedir = g_projects[i].pGamedir; + if ( !pGamedir ) + { + pGamedir = ""; + } + + len = _snprintf( valueBuff, sizeof( valueBuff ), "\"%s\" \"%s\"", pProjectName, pGamedir ); + if ( len == -1 ) + { + // kill it + valueBuff[0] = '\0'; + } + + Sys_SetRegistryString( keyBuff, valueBuff ); + } +} + +//----------------------------------------------------------------------------- +// ShiftActiveProjectUp +// +//----------------------------------------------------------------------------- +void ShiftActiveProjectUp() +{ + if ( g_numProjects <= 1 || !g_nActiveVProject ) + { + // nothing to do + return; + } + + int active = g_nActiveVProject-1; + int previous = (active + g_numProjects - 1) % g_numProjects; + + project_t tempProject; + tempProject = g_projects[previous]; + g_projects[previous] = g_projects[active]; + g_projects[active] = tempProject; + + g_nActiveVProject = previous + 1; +} + +//----------------------------------------------------------------------------- +// ShiftActiveProjectDown +// +//----------------------------------------------------------------------------- +void ShiftActiveProjectDown() +{ + if ( g_numProjects <= 1 || !g_nActiveVProject ) + { + // nothing to do + return; + } + + int active = g_nActiveVProject-1; + int next = (active + g_numProjects + 1) % g_numProjects; + + project_t tempProject; + tempProject = g_projects[next]; + g_projects[next] = g_projects[active]; + g_projects[active] = tempProject; + + g_nActiveVProject = next + 1; +} + +//----------------------------------------------------------------------------- +// ModifyDlg_Proc +// +//----------------------------------------------------------------------------- +BOOL CALLBACK ModifyDlg_Proc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + size_t len; + int width; + int height; + RECT rect; + + switch ( message ) + { + case WM_INITDIALOG: + SetDlgItemText( hWnd, IDC_MODIFY_PROJECT, g_project_name ); + SetDlgItemText( hWnd, IDC_MODIFY_GAMEDIR, g_project_gamedir ); + + // center dialog + GetWindowRect( hWnd, &rect ); + width = GetSystemMetrics( SM_CXSCREEN ); + height = GetSystemMetrics( SM_CYSCREEN ); + SetWindowPos( hWnd, NULL, ( width - ( rect.right - rect.left ) )/2, ( height - ( rect.bottom - rect.top ) )/2, 0, 0, SWP_NOSIZE | SWP_NOZORDER ); + return ( TRUE ); + + case WM_COMMAND: + switch ( LOWORD( wParam ) ) + { + case IDC_OK: + GetDlgItemText( hWnd, IDC_MODIFY_PROJECT, g_project_name, sizeof( g_project_name ) ); + GetDlgItemText( hWnd, IDC_MODIFY_GAMEDIR, g_project_gamedir, sizeof( g_project_gamedir ) ); + + // remove trailing seperator + Sys_NormalizePath( g_project_gamedir, false ); + len = strlen( g_project_gamedir ); + if ( len > 2 && g_project_gamedir[len-1] == '\\' ) + { + g_project_gamedir[len-1] = '\0'; + } + // fall through + + case IDCANCEL: + case IDC_CANCEL: + EndDialog( hWnd, wParam ); + return ( TRUE ); + } + break; + } + return ( FALSE ); +} + +//----------------------------------------------------------------------------- +// ModifyDlg_Open +// +//----------------------------------------------------------------------------- +BOOL ModifyDlg_Open() +{ + int result; + + result = DialogBox( g_hInstance, MAKEINTRESOURCE( IDD_VPROJECT ), g_hWnd, ( DLGPROC )ModifyDlg_Proc ); + if ( LOWORD( result ) != IDC_OK ) + { + return FALSE; + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// ShowPopupMenu +// +//----------------------------------------------------------------------------- +void ShowPopupMenu( HWND hWnd, bool bUseCachedMenuPos ) +{ + BOOL bDelete = true; + + // delete existing entries + for ( int nIndex = 1; nIndex < ID_TRAY_ADDVPROJECT && bDelete; nIndex++ ) + { + bDelete = DeleteMenu( g_hMenu, nIndex, MF_BYCOMMAND ); + } + + // Insert projects + char szMenuItem[MAX_PATH]; + for ( int nIndex = 0; nIndex < g_numProjects; nIndex++ ) + { + strcpy( szMenuItem, g_projects[nIndex].pName ); + strcat( szMenuItem, "\t" ); + strcat( szMenuItem, g_projects[nIndex].pGamedir ); + strcat( szMenuItem, " " ); + + InsertMenu( g_hMenu, nIndex, MF_BYPOSITION | MF_STRING, nIndex + 1, szMenuItem ); + } + + if ( g_nActiveVProject ) + { + CheckMenuItem( g_hMenu, g_nActiveVProject, MF_BYCOMMAND|MF_CHECKED ); + SetMenuDefaultItem( g_hMenu, g_nActiveVProject, FALSE ); + } + + // Display the popup menu at the current cursor location + // Use the cached cursor position if set + if ( !bUseCachedMenuPos || ( !g_cursorPoint.x && !g_cursorPoint.y ) ) + { + GetCursorPos( &g_cursorPoint ); + } + SetForegroundWindow( hWnd ); + TrackPopupMenu( g_hMenu, 0, g_cursorPoint.x, g_cursorPoint.y, 0, hWnd, 0 ); + PostMessage( hWnd, WM_NULL, 0, 0 ); +} + +//----------------------------------------------------------------------------- +// TrayMessageHandler +// +//----------------------------------------------------------------------------- +void TrayMessageHandler( HWND hWnd, UINT uMessageID ) +{ + switch ( uMessageID ) + { + case 0: + break; + + case ID_TRAY_EXIT: + DestroyWindow( hWnd ); + break; + + case ID_TRAY_ADDVPROJECT: + SetForegroundWindow( hWnd ); + g_project_name[0] = '\0'; + g_project_gamedir[0] = '\0'; + if ( ModifyDlg_Open() ) + { + AddVProject( g_project_name, g_project_gamedir ); + SaveRegistryValues(); + } + ShowPopupMenu( hWnd, true ); + break; + + case ID_TRAY_MODIFYVPROJECT: + SetForegroundWindow( hWnd ); + if ( g_nActiveVProject ) + { + strcpy( g_project_name, g_projects[g_nActiveVProject-1].pName ); + strcpy( g_project_gamedir, g_projects[g_nActiveVProject-1].pGamedir ); + if ( ModifyDlg_Open() ) + { + ModifyVProject( g_nActiveVProject-1, g_project_name, g_project_gamedir ); + SaveRegistryValues(); + } + ShowPopupMenu( hWnd, true ); + } + break; + + case ID_TRAY_MOVEUP: + SetForegroundWindow( hWnd ); + if ( g_nActiveVProject ) + { + ShiftActiveProjectUp(); + SaveRegistryValues(); + ShowPopupMenu( hWnd, true ); + } + break; + + case ID_TRAY_MOVEDOWN: + SetForegroundWindow( hWnd ); + if ( g_nActiveVProject ) + { + ShiftActiveProjectDown(); + SaveRegistryValues(); + ShowPopupMenu( hWnd, true ); + } + break; + + default: + if ( uMessageID >= 1 && uMessageID <= MAX_PROJECTS ) + { + // set current vproject + g_nActiveVProject = uMessageID; + SetVProject( g_projects[uMessageID-1].pName ); + } + break; + } +} + +//----------------------------------------------------------------------------- +// Main_WndProc +// +//----------------------------------------------------------------------------- +LRESULT CALLBACK Main_WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + switch ( message ) + { + case WM_DESTROY: + PostQuitMessage( 0 ); + return 0L; + + case WM_TRAY: + if ( lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN ) + { + ShowPopupMenu( hWnd, false ); + return 0L; + } + break; + + case WM_COMMAND: + TrayMessageHandler( hWnd, LOWORD( wParam ) ); + break; + } + + return ( DefWindowProc( hWnd, message, wParam, lParam ) ); +} + +//----------------------------------------------------------------------------- +// Startup +// +//----------------------------------------------------------------------------- +bool Startup() +{ + int i; + + // set up our window class + WNDCLASS wndclass; + memset( &wndclass, 0, sizeof( wndclass ) ); + wndclass.style = 0; + wndclass.lpfnWndProc = Main_WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = g_hInstance; + wndclass.hIcon = LoadIcon( g_hInstance, (LPCTSTR)IDI_VPROJECT ); + wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); + wndclass.hbrBackground = NULL; + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = VPROJECT_CLASSNAME; + if ( !RegisterClass( &wndclass ) ) + { + return false; + } + + // create the hidden window + g_hWnd = CreateWindow( + VPROJECT_CLASSNAME, + 0, + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + 0, + CW_USEDEFAULT, + 0, + NULL, + NULL, + g_hInstance, + NULL ); + + // Create tray icon + g_iconData.cbSize = sizeof( NOTIFYICONDATA ); + g_iconData.hIcon = LoadIcon( g_hInstance, (LPCTSTR)IDI_VPROJECT ); + g_iconData.hWnd = g_hWnd; + g_iconData.uCallbackMessage = WM_TRAY; + g_iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; + g_iconData.uID = ID_TRAY; + strcpy(g_iconData.szTip, "VPROJECT"); + Shell_NotifyIcon( NIM_ADD, &g_iconData ); + + // Create popup menu and add initial items + g_hMenu = CreatePopupMenu(); + AppendMenu( g_hMenu, MF_SEPARATOR, 0, 0); + AppendMenu( g_hMenu, MF_STRING, ID_TRAY_ADDVPROJECT, "Add VProject" ); + AppendMenu( g_hMenu, MF_STRING, ID_TRAY_MODIFYVPROJECT, "Modify VProject" ); + AppendMenu( g_hMenu, MF_STRING, ID_TRAY_MOVEUP, "Move Up" ); + AppendMenu( g_hMenu, MF_STRING, ID_TRAY_MOVEDOWN, "Move Down" ); + AppendMenu( g_hMenu, MF_SEPARATOR, 0, 0); + AppendMenu( g_hMenu, MF_STRING, ID_TRAY_EXIT, "Remove From Tray" ); + + // find the current vproject + char* vproject = getenv( "vproject" ); + if ( vproject && vproject[0] ) + { + char temp[MAX_PATH]; + strcpy( temp, vproject ); + Sys_NormalizePath( temp, false ); + for ( i=0; i<g_numProjects; i++ ) + { + if ( !stricmp( g_projects[i].pGamedir, temp ) ) + { + // found + g_nActiveVProject = i+1; + break; + } + } + } + + return true; +} + +//----------------------------------------------------------------------------- +// Shutdown +// +// Free all resources +//----------------------------------------------------------------------------- +void Shutdown() +{ +} + +//----------------------------------------------------------------------------- +// WinMain +// +// Entry point for program +//----------------------------------------------------------------------------- +int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow ) +{ + bool error = true; + MSG msg = {0}; + + g_hInstance = hInstance; + + // get the project list + LoadRegistryValues(); + + if ( pCmdLine && pCmdLine[0] ) + { + // set directly + SetVProject( pCmdLine ); + return 0; + } + + HWND hwnd = FindWindow( VPROJECT_CLASSNAME, NULL ); + if ( hwnd ) + { + // single instance only + return ( FALSE ); + } + + if ( !Startup() ) + { + goto cleanUp; + } + + // message pump + while ( GetMessage( &msg, NULL, 0, 0 ) ) + { + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + + // no-error, end of app + error = false; + +cleanUp: + if ( error ) + { + char str[255]; + FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), 0, str, 255, NULL ); + MessageBox( NULL, str, NULL, MB_OK ); + } + + Shutdown(); + + return ( (int)msg.wParam ); +} + + |