Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

648 lines
15 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // VPROJECT.CPP
  4. //
  5. //=====================================================================================//
  6. #include "vproject.h"
  7. #define MAX_PROJECTS 50
  8. #define ID_PROJECTS_LISTVIEW 100
  9. // column id
  10. #define ID_PROJECT_NAME 0
  11. #define ID_PROJECT_DIRECTORY 1
  12. #define WM_TRAY (WM_APP + 1)
  13. #define ID_TRAY 5000
  14. #define ID_TRAY_ADDVPROJECT 6000
  15. #define ID_TRAY_MODIFYVPROJECT 6001
  16. #define ID_TRAY_MOVEUP 6002
  17. #define ID_TRAY_MOVEDOWN 6003
  18. #define ID_TRAY_EXIT 6004
  19. typedef struct
  20. {
  21. char *pName;
  22. char *pGamedir;
  23. } project_t;
  24. HWND g_hWnd;
  25. char g_project_name[256];
  26. char g_project_gamedir[256];
  27. HINSTANCE g_hInstance;
  28. project_t g_projects[MAX_PROJECTS];
  29. int g_numProjects;
  30. NOTIFYICONDATA g_iconData;
  31. HMENU g_hMenu;
  32. int g_nActiveVProject;
  33. POINT g_cursorPoint;
  34. void TrayMessageHandler( HWND hWnd, UINT uMessageID );
  35. //-----------------------------------------------------------------------------
  36. // SetVProject
  37. //
  38. //-----------------------------------------------------------------------------
  39. void SetVProject( const char *pProjectName )
  40. {
  41. char *pGamedir;
  42. char project[256];
  43. int i;
  44. if ( pProjectName )
  45. {
  46. strcpy( project, pProjectName );
  47. Sys_StripQuotesFromToken( project );
  48. for ( i=0; i<g_numProjects; i++ )
  49. {
  50. if ( !stricmp( g_projects[i].pName, project ) )
  51. {
  52. // found
  53. break;
  54. }
  55. }
  56. if ( i >= g_numProjects )
  57. {
  58. // not found
  59. return;
  60. }
  61. pGamedir = g_projects[i].pGamedir;
  62. }
  63. else
  64. {
  65. pGamedir = "";
  66. }
  67. // Changed to CURRENT_USER to solve security issues in vista!
  68. Sys_SetRegistryString(
  69. //"HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\Environment\\VProject",
  70. "HKEY_CURRENT_USER\\Environment\\VProject"
  71. pGamedir );
  72. DWORD result;
  73. SendMessageTimeout(
  74. HWND_BROADCAST,
  75. WM_SETTINGCHANGE,
  76. 0,
  77. (LPARAM)"Environment",
  78. SMTO_ABORTIFHUNG,
  79. 0,
  80. &result );
  81. }
  82. //-----------------------------------------------------------------------------
  83. // ModifyVProject
  84. //
  85. //-----------------------------------------------------------------------------
  86. void ModifyVProject( int index, const char *pName, const char *pGamedir )
  87. {
  88. free( g_projects[index].pName );
  89. free( g_projects[index].pGamedir );
  90. if ( !pName || !pName[0] )
  91. {
  92. // delete
  93. if ( g_numProjects-index-1 > 0 )
  94. {
  95. // shift remaining elements
  96. memcpy( &g_projects[index], &g_projects[index+1], (g_numProjects-index-1)*sizeof( project_t ) );
  97. }
  98. g_projects[g_numProjects-1].pName = NULL;
  99. g_projects[g_numProjects-1].pGamedir = NULL;
  100. g_numProjects--;
  101. if ( g_nActiveVProject == index+1 )
  102. {
  103. // deleted current vproject
  104. if ( !g_numProjects )
  105. {
  106. // no more projects
  107. g_nActiveVProject = 0;
  108. SetVProject( NULL );
  109. }
  110. else
  111. {
  112. // set to top
  113. g_nActiveVProject = 1;
  114. SetVProject( g_projects[0].pName );
  115. }
  116. }
  117. }
  118. else
  119. {
  120. g_projects[index].pName = strdup( pName );
  121. g_projects[index].pGamedir = strdup( pGamedir );
  122. }
  123. }
  124. //-----------------------------------------------------------------------------
  125. // AddVProject
  126. //
  127. //-----------------------------------------------------------------------------
  128. void AddVProject( const char *pName, const char *pGamedir )
  129. {
  130. if ( !pName || !pName[0] )
  131. {
  132. // do not add empty projects
  133. return;
  134. }
  135. ModifyVProject( g_numProjects, pName, pGamedir );
  136. g_numProjects++;
  137. }
  138. //-----------------------------------------------------------------------------
  139. // LoadRegistryValues
  140. //
  141. //-----------------------------------------------------------------------------
  142. void LoadRegistryValues()
  143. {
  144. char keyBuff[32];
  145. char valueBuff[256];
  146. char projectName[256];
  147. char gamedirString[256];
  148. char *ptr;
  149. char *token;
  150. int i;
  151. for ( i=0; i<MAX_PROJECTS; i++ )
  152. {
  153. projectName[0] = '\0';
  154. gamedirString[0] = '\0';
  155. sprintf( keyBuff, "project%d", i );
  156. Sys_GetRegistryString( keyBuff, valueBuff, "", sizeof( valueBuff ) );
  157. // parse and populate valid values
  158. ptr = valueBuff;
  159. token = Sys_GetToken( &ptr, false, NULL );
  160. if ( token[0] )
  161. {
  162. strcpy( projectName, token );
  163. }
  164. else
  165. {
  166. continue;
  167. }
  168. token = Sys_GetToken( &ptr, false, NULL );
  169. if ( token[0] )
  170. {
  171. strcpy( gamedirString, token );
  172. }
  173. AddVProject( projectName, gamedirString );
  174. }
  175. }
  176. //-----------------------------------------------------------------------------
  177. // SaveRegistryValues
  178. //
  179. //-----------------------------------------------------------------------------
  180. void SaveRegistryValues()
  181. {
  182. char valueBuff[256];
  183. char keyBuff[32];
  184. char *pProjectName;
  185. char *pGamedir;
  186. int len;
  187. int i;
  188. for ( i=0; i<MAX_PROJECTS; i++ )
  189. {
  190. sprintf( keyBuff, "project%d", i );
  191. pProjectName = g_projects[i].pName;
  192. if ( !pProjectName )
  193. {
  194. pProjectName = "";
  195. }
  196. pGamedir = g_projects[i].pGamedir;
  197. if ( !pGamedir )
  198. {
  199. pGamedir = "";
  200. }
  201. len = _snprintf( valueBuff, sizeof( valueBuff ), "\"%s\" \"%s\"", pProjectName, pGamedir );
  202. if ( len == -1 )
  203. {
  204. // kill it
  205. valueBuff[0] = '\0';
  206. }
  207. Sys_SetRegistryString( keyBuff, valueBuff );
  208. }
  209. }
  210. //-----------------------------------------------------------------------------
  211. // ShiftActiveProjectUp
  212. //
  213. //-----------------------------------------------------------------------------
  214. void ShiftActiveProjectUp()
  215. {
  216. if ( g_numProjects <= 1 || !g_nActiveVProject )
  217. {
  218. // nothing to do
  219. return;
  220. }
  221. int active = g_nActiveVProject-1;
  222. int previous = (active + g_numProjects - 1) % g_numProjects;
  223. project_t tempProject;
  224. tempProject = g_projects[previous];
  225. g_projects[previous] = g_projects[active];
  226. g_projects[active] = tempProject;
  227. g_nActiveVProject = previous + 1;
  228. }
  229. //-----------------------------------------------------------------------------
  230. // ShiftActiveProjectDown
  231. //
  232. //-----------------------------------------------------------------------------
  233. void ShiftActiveProjectDown()
  234. {
  235. if ( g_numProjects <= 1 || !g_nActiveVProject )
  236. {
  237. // nothing to do
  238. return;
  239. }
  240. int active = g_nActiveVProject-1;
  241. int next = (active + g_numProjects + 1) % g_numProjects;
  242. project_t tempProject;
  243. tempProject = g_projects[next];
  244. g_projects[next] = g_projects[active];
  245. g_projects[active] = tempProject;
  246. g_nActiveVProject = next + 1;
  247. }
  248. //-----------------------------------------------------------------------------
  249. // ModifyDlg_Proc
  250. //
  251. //-----------------------------------------------------------------------------
  252. BOOL CALLBACK ModifyDlg_Proc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
  253. {
  254. size_t len;
  255. int width;
  256. int height;
  257. RECT rect;
  258. switch ( message )
  259. {
  260. case WM_INITDIALOG:
  261. SetDlgItemText( hWnd, IDC_MODIFY_PROJECT, g_project_name );
  262. SetDlgItemText( hWnd, IDC_MODIFY_GAMEDIR, g_project_gamedir );
  263. // center dialog
  264. GetWindowRect( hWnd, &rect );
  265. width = GetSystemMetrics( SM_CXSCREEN );
  266. height = GetSystemMetrics( SM_CYSCREEN );
  267. SetWindowPos( hWnd, NULL, ( width - ( rect.right - rect.left ) )/2, ( height - ( rect.bottom - rect.top ) )/2, 0, 0, SWP_NOSIZE | SWP_NOZORDER );
  268. return ( TRUE );
  269. case WM_COMMAND:
  270. switch ( LOWORD( wParam ) )
  271. {
  272. case IDC_OK:
  273. GetDlgItemText( hWnd, IDC_MODIFY_PROJECT, g_project_name, sizeof( g_project_name ) );
  274. GetDlgItemText( hWnd, IDC_MODIFY_GAMEDIR, g_project_gamedir, sizeof( g_project_gamedir ) );
  275. // remove trailing seperator
  276. Sys_NormalizePath( g_project_gamedir, false );
  277. len = strlen( g_project_gamedir );
  278. if ( len > 2 && g_project_gamedir[len-1] == '\\' )
  279. {
  280. g_project_gamedir[len-1] = '\0';
  281. }
  282. // fall through
  283. case IDCANCEL:
  284. case IDC_CANCEL:
  285. EndDialog( hWnd, wParam );
  286. return ( TRUE );
  287. }
  288. break;
  289. }
  290. return ( FALSE );
  291. }
  292. //-----------------------------------------------------------------------------
  293. // ModifyDlg_Open
  294. //
  295. //-----------------------------------------------------------------------------
  296. BOOL ModifyDlg_Open()
  297. {
  298. int result;
  299. result = DialogBox( g_hInstance, MAKEINTRESOURCE( IDD_VPROJECT ), g_hWnd, ( DLGPROC )ModifyDlg_Proc );
  300. if ( LOWORD( result ) != IDC_OK )
  301. {
  302. return FALSE;
  303. }
  304. return TRUE;
  305. }
  306. //-----------------------------------------------------------------------------
  307. // ShowPopupMenu
  308. //
  309. //-----------------------------------------------------------------------------
  310. void ShowPopupMenu( HWND hWnd, bool bUseCachedMenuPos )
  311. {
  312. BOOL bDelete = true;
  313. // delete existing entries
  314. for ( int nIndex = 1; nIndex < ID_TRAY_ADDVPROJECT && bDelete; nIndex++ )
  315. {
  316. bDelete = DeleteMenu( g_hMenu, nIndex, MF_BYCOMMAND );
  317. }
  318. // Insert projects
  319. char szMenuItem[MAX_PATH];
  320. for ( int nIndex = 0; nIndex < g_numProjects; nIndex++ )
  321. {
  322. strcpy( szMenuItem, g_projects[nIndex].pName );
  323. strcat( szMenuItem, "\t" );
  324. strcat( szMenuItem, g_projects[nIndex].pGamedir );
  325. strcat( szMenuItem, " " );
  326. InsertMenu( g_hMenu, nIndex, MF_BYPOSITION | MF_STRING, nIndex + 1, szMenuItem );
  327. }
  328. if ( g_nActiveVProject )
  329. {
  330. CheckMenuItem( g_hMenu, g_nActiveVProject, MF_BYCOMMAND|MF_CHECKED );
  331. SetMenuDefaultItem( g_hMenu, g_nActiveVProject, FALSE );
  332. }
  333. // Display the popup menu at the current cursor location
  334. // Use the cached cursor position if set
  335. if ( !bUseCachedMenuPos || ( !g_cursorPoint.x && !g_cursorPoint.y ) )
  336. {
  337. GetCursorPos( &g_cursorPoint );
  338. }
  339. SetForegroundWindow( hWnd );
  340. TrackPopupMenu( g_hMenu, 0, g_cursorPoint.x, g_cursorPoint.y, 0, hWnd, 0 );
  341. PostMessage( hWnd, WM_NULL, 0, 0 );
  342. }
  343. //-----------------------------------------------------------------------------
  344. // TrayMessageHandler
  345. //
  346. //-----------------------------------------------------------------------------
  347. void TrayMessageHandler( HWND hWnd, UINT uMessageID )
  348. {
  349. switch ( uMessageID )
  350. {
  351. case 0:
  352. break;
  353. case ID_TRAY_EXIT:
  354. DestroyWindow( hWnd );
  355. break;
  356. case ID_TRAY_ADDVPROJECT:
  357. SetForegroundWindow( hWnd );
  358. g_project_name[0] = '\0';
  359. g_project_gamedir[0] = '\0';
  360. if ( ModifyDlg_Open() )
  361. {
  362. AddVProject( g_project_name, g_project_gamedir );
  363. SaveRegistryValues();
  364. }
  365. ShowPopupMenu( hWnd, true );
  366. break;
  367. case ID_TRAY_MODIFYVPROJECT:
  368. SetForegroundWindow( hWnd );
  369. if ( g_nActiveVProject )
  370. {
  371. strcpy( g_project_name, g_projects[g_nActiveVProject-1].pName );
  372. strcpy( g_project_gamedir, g_projects[g_nActiveVProject-1].pGamedir );
  373. if ( ModifyDlg_Open() )
  374. {
  375. ModifyVProject( g_nActiveVProject-1, g_project_name, g_project_gamedir );
  376. SaveRegistryValues();
  377. }
  378. ShowPopupMenu( hWnd, true );
  379. }
  380. break;
  381. case ID_TRAY_MOVEUP:
  382. SetForegroundWindow( hWnd );
  383. if ( g_nActiveVProject )
  384. {
  385. ShiftActiveProjectUp();
  386. SaveRegistryValues();
  387. ShowPopupMenu( hWnd, true );
  388. }
  389. break;
  390. case ID_TRAY_MOVEDOWN:
  391. SetForegroundWindow( hWnd );
  392. if ( g_nActiveVProject )
  393. {
  394. ShiftActiveProjectDown();
  395. SaveRegistryValues();
  396. ShowPopupMenu( hWnd, true );
  397. }
  398. break;
  399. default:
  400. if ( uMessageID >= 1 && uMessageID <= MAX_PROJECTS )
  401. {
  402. // set current vproject
  403. g_nActiveVProject = uMessageID;
  404. SetVProject( g_projects[uMessageID-1].pName );
  405. }
  406. break;
  407. }
  408. }
  409. //-----------------------------------------------------------------------------
  410. // Main_WndProc
  411. //
  412. //-----------------------------------------------------------------------------
  413. LRESULT CALLBACK Main_WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
  414. {
  415. switch ( message )
  416. {
  417. case WM_DESTROY:
  418. PostQuitMessage( 0 );
  419. return 0L;
  420. case WM_TRAY:
  421. if ( lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN )
  422. {
  423. ShowPopupMenu( hWnd, false );
  424. return 0L;
  425. }
  426. break;
  427. case WM_COMMAND:
  428. TrayMessageHandler( hWnd, LOWORD( wParam ) );
  429. break;
  430. }
  431. return ( DefWindowProc( hWnd, message, wParam, lParam ) );
  432. }
  433. //-----------------------------------------------------------------------------
  434. // Startup
  435. //
  436. //-----------------------------------------------------------------------------
  437. bool Startup()
  438. {
  439. int i;
  440. // set up our window class
  441. WNDCLASS wndclass;
  442. memset( &wndclass, 0, sizeof( wndclass ) );
  443. wndclass.style = 0;
  444. wndclass.lpfnWndProc = Main_WndProc;
  445. wndclass.cbClsExtra = 0;
  446. wndclass.cbWndExtra = 0;
  447. wndclass.hInstance = g_hInstance;
  448. wndclass.hIcon = LoadIcon( g_hInstance, (LPCTSTR)IDI_VPROJECT );
  449. wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
  450. wndclass.hbrBackground = NULL;
  451. wndclass.lpszMenuName = NULL;
  452. wndclass.lpszClassName = VPROJECT_CLASSNAME;
  453. if ( !RegisterClass( &wndclass ) )
  454. {
  455. return false;
  456. }
  457. // create the hidden window
  458. g_hWnd = CreateWindow(
  459. VPROJECT_CLASSNAME,
  460. 0,
  461. WS_OVERLAPPEDWINDOW,
  462. CW_USEDEFAULT,
  463. 0,
  464. CW_USEDEFAULT,
  465. 0,
  466. NULL,
  467. NULL,
  468. g_hInstance,
  469. NULL );
  470. // Create tray icon
  471. g_iconData.cbSize = sizeof( NOTIFYICONDATA );
  472. g_iconData.hIcon = LoadIcon( g_hInstance, (LPCTSTR)IDI_VPROJECT );
  473. g_iconData.hWnd = g_hWnd;
  474. g_iconData.uCallbackMessage = WM_TRAY;
  475. g_iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  476. g_iconData.uID = ID_TRAY;
  477. strcpy(g_iconData.szTip, "VPROJECT");
  478. Shell_NotifyIcon( NIM_ADD, &g_iconData );
  479. // Create popup menu and add initial items
  480. g_hMenu = CreatePopupMenu();
  481. AppendMenu( g_hMenu, MF_SEPARATOR, 0, 0);
  482. AppendMenu( g_hMenu, MF_STRING, ID_TRAY_ADDVPROJECT, "Add VProject" );
  483. AppendMenu( g_hMenu, MF_STRING, ID_TRAY_MODIFYVPROJECT, "Modify VProject" );
  484. AppendMenu( g_hMenu, MF_STRING, ID_TRAY_MOVEUP, "Move Up" );
  485. AppendMenu( g_hMenu, MF_STRING, ID_TRAY_MOVEDOWN, "Move Down" );
  486. AppendMenu( g_hMenu, MF_SEPARATOR, 0, 0);
  487. AppendMenu( g_hMenu, MF_STRING, ID_TRAY_EXIT, "Remove From Tray" );
  488. // find the current vproject
  489. char* vproject = getenv( "vproject" );
  490. if ( vproject && vproject[0] )
  491. {
  492. char temp[MAX_PATH];
  493. strcpy( temp, vproject );
  494. Sys_NormalizePath( temp, false );
  495. for ( i=0; i<g_numProjects; i++ )
  496. {
  497. if ( !stricmp( g_projects[i].pGamedir, temp ) )
  498. {
  499. // found
  500. g_nActiveVProject = i+1;
  501. break;
  502. }
  503. }
  504. }
  505. return true;
  506. }
  507. //-----------------------------------------------------------------------------
  508. // Shutdown
  509. //
  510. // Free all resources
  511. //-----------------------------------------------------------------------------
  512. void Shutdown()
  513. {
  514. }
  515. //-----------------------------------------------------------------------------
  516. // WinMain
  517. //
  518. // Entry point for program
  519. //-----------------------------------------------------------------------------
  520. int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow )
  521. {
  522. bool error = true;
  523. MSG msg = {0};
  524. g_hInstance = hInstance;
  525. // get the project list
  526. LoadRegistryValues();
  527. if ( pCmdLine && pCmdLine[0] )
  528. {
  529. // set directly
  530. SetVProject( pCmdLine );
  531. return 0;
  532. }
  533. HWND hwnd = FindWindow( VPROJECT_CLASSNAME, NULL );
  534. if ( hwnd )
  535. {
  536. // single instance only
  537. return ( FALSE );
  538. }
  539. if ( !Startup() )
  540. {
  541. goto cleanUp;
  542. }
  543. // message pump
  544. while ( GetMessage( &msg, NULL, 0, 0 ) )
  545. {
  546. TranslateMessage( &msg );
  547. DispatchMessage( &msg );
  548. }
  549. // no-error, end of app
  550. error = false;
  551. cleanUp:
  552. if ( error )
  553. {
  554. char str[255];
  555. FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), 0, str, 255, NULL );
  556. MessageBox( NULL, str, NULL, MB_OK );
  557. }
  558. Shutdown();
  559. return ( (int)msg.wParam );
  560. }