Source code of Windows XP (NT5)
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.

3152 lines
78 KiB

  1. //***************************************************************************
  2. //
  3. // QuickRes for Windows NT and Windows 9x
  4. //
  5. // Tray app to change your display resolution quickly.
  6. //
  7. // written by ToddLa
  8. //
  9. // 03/03/96 - ChrisW : Get to build on NT
  10. // 03/28/96 - MDesai : Finish porting; add submenus with frequencies;
  11. // Test for valid devmode.
  12. // 04/23/96 - MDesai : option for 'showing tested modes only'
  13. // 10/01/96 - MDesai : fix all win95-specific bugs
  14. // 11/03/98 - MDesai : 'multimonitor aware'
  15. // 12/02/99 - MDesai : better multimon support
  16. //
  17. //***************************************************************************
  18. #include "QuickRes.h"
  19. PTCHAR szAppName;
  20. HINSTANCE hInstApp;
  21. HICON AppIcon;
  22. //
  23. // options, properties, about and exit...
  24. // monitor menu
  25. //
  26. HMENU MainMenu;
  27. HMENU MonitorMenu=NULL;
  28. //
  29. // number of monitors/display devices installed
  30. // pointer to monitorinfo struct for each monitor
  31. //
  32. INT iMonitors;
  33. LPQRMONITORINFO pMonitors;
  34. //
  35. // Waiting for a Popup - don't process any tray messages
  36. //
  37. BOOL Waiting=FALSE;
  38. //
  39. // Flags: update registry, show restart modes, sort order
  40. // also where the freq menu(s) go.
  41. //
  42. WORD QuickResFlags;
  43. WORD FreqMenuLocation;
  44. //
  45. // Function pointers for NT5
  46. //
  47. FARPROC lpfnEDSEx=NULL;
  48. FARPROC lpfnEDD=NULL;
  49. //
  50. //***************************************************************************
  51. //
  52. // GetResourceString( UINT )
  53. //
  54. // Load a resource string into a LPTSTR - the memory for the string
  55. // is dynamically allocated. The callee must free the memory!
  56. //
  57. //***************************************************************************
  58. //
  59. LPTSTR GetResourceString ( UINT ResourceID )
  60. {
  61. INT BuffSize=RESOURCE_STRINGLEN; // current max size of string
  62. PTCHAR BigBuf; // buffer to find size of resource
  63. PTCHAR ResBuf; // buffer for resource
  64. INT len; // length of the resource
  65. while (1)
  66. {
  67. //
  68. // Allocate hopefully oversized buffer
  69. //
  70. if( !(BigBuf= LocalAlloc( LPTR, BuffSize ) ) )
  71. {
  72. return NULL;
  73. }
  74. //
  75. // Try to read string into BigBuf to get its length
  76. //
  77. if ( !(len = LoadString(hInstApp, ResourceID, BigBuf, BuffSize)) )
  78. {
  79. return NULL;
  80. }
  81. //
  82. // Buffer is too small - try again.
  83. //
  84. if( len >= BuffSize-1 )
  85. {
  86. BuffSize <<= 1;
  87. LocalFree ( BigBuf );
  88. }
  89. else
  90. {
  91. //
  92. // Reallocate properly sized string buffer,
  93. // and copy string into it
  94. //
  95. len = ( len + 1 ) * sizeof( TCHAR );
  96. if (ResBuf = LocalAlloc( LPTR, len ))
  97. {
  98. lstrcpyn ( ResBuf, BigBuf, len );
  99. }
  100. LocalFree ( BigBuf );
  101. return( ResBuf );
  102. }
  103. }
  104. }
  105. //
  106. //***************************************************************************
  107. //
  108. // GetModeName( PDEVMODE, PTCHAR*, PTCHAR* )
  109. //
  110. // Translate devmode into user friendly strings-
  111. // one for resolution and color depth; one for refresh rate
  112. //
  113. //***************************************************************************
  114. //
  115. void GetModeName(PDEVMODE pDevMode, PTCHAR *szMode, PTCHAR *szFreq )
  116. {
  117. PTCHAR FmtRes=NULL; // Format strings for
  118. PTCHAR FmtHz=NULL; // resolution and Hz
  119. //
  120. // Load format string corresponding to devmode
  121. //
  122. FmtRes = GetResourceString ( IDS_CRES + BPP(pDevMode) );
  123. //
  124. // Use Default Freq string if necessary
  125. //
  126. if (fShowFreqs)
  127. {
  128. if( HZ(pDevMode) == 0 || HZ(pDevMode) == 1)
  129. {
  130. FmtHz = GetResourceString ( IDS_DEFHERTZ );
  131. }
  132. else
  133. {
  134. FmtHz = GetResourceString ( IDS_HERTZ );
  135. }
  136. }
  137. //
  138. // return separate resolution and frequency strings
  139. // need to convert "%d"-> "12345", add byte for '\0'
  140. //
  141. if (FmtRes)
  142. {
  143. if (*szMode = LocalAlloc( LPTR, sizeof(TCHAR)*
  144. (lstrlen(FmtRes)+2*INT_FORMAT_TO_5_DIGITS+1 ) ))
  145. {
  146. wsprintf(*szMode, FmtRes, XRES(pDevMode), YRES(pDevMode) );
  147. }
  148. LocalFree ( FmtRes );
  149. }
  150. if (fShowFreqs && FmtHz)
  151. {
  152. if (*szFreq = LocalAlloc ( LPTR, sizeof(TCHAR)*
  153. (lstrlen(FmtHz)+INT_FORMAT_TO_5_DIGITS+1) ))
  154. {
  155. wsprintf(*szFreq, FmtHz, HZ(pDevMode));
  156. }
  157. LocalFree ( FmtHz );
  158. }
  159. }
  160. //
  161. //***************************************************************************
  162. //
  163. // GetCurrentDevMode( INT, PDEVMODE )
  164. //
  165. // Get a pointer to the current devmode into *pDM
  166. //
  167. //***************************************************************************
  168. //
  169. PDEVMODE GetCurrentDevMode(INT iDisplay, PDEVMODE pDM)
  170. {
  171. UINT uRet=0;
  172. pDM->dmSize= sizeof(DEVMODE);
  173. //
  174. // NT specific; returns current devmode
  175. //
  176. if (fShowFreqs)
  177. {
  178. uRet = EnumDisplaySettings( pMonitors[iDisplay].DeviceName, (DWORD)ENUM_CURRENT_SETTINGS, pDM);
  179. }
  180. if (!uRet)
  181. {
  182. //
  183. // ENUM_CURRENT_SETTINGS doesnt work on win95
  184. // Get current settings via GetDeviceCaps
  185. //
  186. HDC hDC;
  187. UINT HorzRes;
  188. UINT VertRes;
  189. UINT BPP;
  190. UINT VRefresh;
  191. UINT Index;
  192. hDC = GetDC( NULL );
  193. HorzRes = GetDeviceCaps( hDC, HORZRES );
  194. VertRes = GetDeviceCaps( hDC, VERTRES );
  195. BPP = GetDeviceCaps( hDC, BITSPIXEL ) * GetDeviceCaps( hDC, PLANES );
  196. VRefresh = GetDeviceCaps( hDC, VREFRESH );
  197. //
  198. // Enumerate all settings until one matches our current settings
  199. //
  200. for ( Index=0;
  201. EnumDisplaySettings( pMonitors[iDisplay].DeviceName, Index, pDM);
  202. Index++ )
  203. {
  204. if ( HorzRes == XRES(pDM) &&
  205. VertRes == YRES(pDM) &&
  206. BPP == BPP(pDM)
  207. )
  208. {
  209. //
  210. // if frequency matters, then check for it
  211. //
  212. if (!fShowFreqs || (VRefresh == HZ(pDM)) )
  213. break;
  214. }
  215. }
  216. ReleaseDC (NULL, hDC);
  217. }
  218. return pDM;
  219. }
  220. //
  221. //***************************************************************************
  222. //
  223. // SetMode( HWND, UINT )
  224. //
  225. // Set the new devmode and update registry on request using
  226. // the CDS_UPDATEREGISTRY flag. If user wants to change and
  227. // restart, then we need to update the registry and restart.
  228. //
  229. //***************************************************************************
  230. //
  231. BOOL SetMode( HWND hwnd, INT iDisplay, UINT index )
  232. {
  233. DWORD CDSret=0; // ret value, ChangeDisplaySettings
  234. DWORD CDSFlags=0; // 2nd param of call to CDS
  235. INT_PTR DialogBoxRet=0; // IDYES/NO/ABORT/CANCEL
  236. LPDEVMODEINFO pSave; // save ptr in iDisplay to remember orig mode
  237. LPDEVMODEINFO pdm; // new mode to be set
  238. BOOL bChange=FALSE; // changing modes or not
  239. LPQRMONITORINFO pCurrMon; // ptr to current monitorinfo strcut
  240. pCurrMon = &pMonitors[iDisplay];
  241. //
  242. // Save current mode; find ptr to new mode
  243. //
  244. pSave = pCurrMon->pCurrentdm;
  245. pdm = &(pCurrMon->pModes[index]);
  246. //
  247. // If user wants to update registry
  248. //
  249. if( fUpdateReg )
  250. {
  251. CDSFlags |= CDS_UPDATEREGISTRY;
  252. }
  253. //
  254. // Tell CDS what fields may be changing
  255. // Also, keep appwndproc from doing anything while we are testing
  256. //
  257. pdm->dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
  258. Waiting=TRUE;
  259. //
  260. // Call CDS and update registry on request. (If it is
  261. // a known bad mode give user chance to change his mind.)
  262. //
  263. if( (VALIDMODE(pdm) != MODE_INVALID ) ||
  264. ( MsgBox( IDS_INVALIDMODE, 0, MB_YESNO | MB_ICONQUESTION )==IDYES ) )
  265. {
  266. CDSret = ChangeDisplaySettingsEx( pCurrMon->DeviceName, &(pdm->dm), NULL, CDSFlags, 0);
  267. if (CDSret == DISP_CHANGE_SUCCESSFUL)
  268. {
  269. //
  270. // Even though it may be temporary, current dm has changed.
  271. // Need to reset pCurrentdm to point to new current DM.
  272. // Change tooltip to reflect old settings
  273. //
  274. pCurrMon->pCurrentdm = pdm;
  275. TrayMessage(hwnd, NIM_MODIFY, TRAY_ID, AppIcon);
  276. //
  277. // Return value claims that it 'worked.' But, it may not visible
  278. // to the user (e.g. the mode is unsupported by the monitor).
  279. // If the User has not already approved this new resolution,
  280. // then make the user approve the change, or we default back to
  281. // the last devmode.
  282. //
  283. if ( fGoodMode(pdm) )
  284. {
  285. //
  286. // VALID or BESTHZ modes - go ahead and change
  287. //
  288. bChange = TRUE;
  289. }
  290. else
  291. {
  292. //
  293. // Ask user if it looks okay
  294. // Flag the mode based on return value.
  295. //
  296. switch( DialogBoxRet = DialogBoxParam( hInstApp,
  297. MAKEINTRESOURCE(KeepNewRes),
  298. NULL,
  299. KeepNewResDlgProc,
  300. iDisplay) )
  301. {
  302. //
  303. // There should NOT be a break after
  304. // IDYES. Fall thru by design.
  305. //
  306. case IDYES: bChange = TRUE;
  307. case IDABORT: VALIDMODE(pdm) = MODE_VALID;
  308. break;
  309. case IDNO:
  310. case IDCANCEL: VALIDMODE(pdm) = MODE_INVALID;
  311. break;
  312. } // switch
  313. } // else - MODE_INVALID
  314. }
  315. if (CDSret != DISP_CHANGE_SUCCESSFUL)
  316. {
  317. //
  318. // Requires restart. Ask user if thats okay.
  319. //
  320. if (CDSret == DISP_CHANGE_RESTART)
  321. {
  322. if ( MsgBox(IDS_RESTART, 0, MB_YESNO | MB_ICONQUESTION) == IDYES )
  323. {
  324. //
  325. // After restart all modes will need to be tested again?
  326. //
  327. SetDevmodeFlags ( iDisplay, TRUE );
  328. //
  329. // Call CDS again to update registry
  330. //
  331. ChangeDisplaySettingsEx( pCurrMon->DeviceName, &(pdm->dm), NULL,
  332. (CDSFlags | CDS_UPDATEREGISTRY), 0);
  333. ExitWindowsEx(EWX_REBOOT, 0);
  334. }
  335. }
  336. else
  337. {
  338. //
  339. // Tell user we cannot change to this devmode
  340. //
  341. MsgBox(IDS_CANTSETMODE, 0, MB_OK | MB_ICONEXCLAMATION);
  342. }
  343. } // end else != DISP_CHANGE_SUCCESSFUL
  344. if (bChange)
  345. {
  346. //
  347. // Changing to a valid mode; destroy and rebuild menu
  348. // Mark mode we were just in as valid (if it wasnt already)
  349. //
  350. VALIDMODE(pSave) |= MODE_VALID;
  351. //
  352. // This is the new "Best Hz" mode. The old mode is 'only valid'.
  353. //
  354. if ((FreqMenuLocation == IDD_ONEMENUMOBILE) ||
  355. (FreqMenuLocation == IDD_ONEMENUBOTTOM) )
  356. {
  357. VALIDMODE(pCurrMon->pCurrentdm) = MODE_BESTHZ;
  358. }
  359. DestroyModeMenu( iDisplay, TRUE, FALSE );
  360. }
  361. else // !bChange
  362. {
  363. //
  364. // Change back to last good devmode; do not have to recheck menuitems
  365. //
  366. pCurrMon->pCurrentdm = pSave;
  367. //
  368. // Change back, and reset registry IF we had set it above
  369. // Change tooltip to reflect old settings
  370. //
  371. if (CDSret != DISP_CHANGE_RESTART)
  372. {
  373. ChangeDisplaySettingsEx( pCurrMon->DeviceName, &(pCurrMon->pCurrentdm->dm),
  374. NULL, CDSFlags, 0);
  375. }
  376. TrayMessage(hwnd, NIM_MODIFY, TRAY_ID, AppIcon);
  377. } // bChange
  378. } // endif
  379. //
  380. // Save new settings for this devmode to the registry.
  381. // Even if quickres does not exit gracefully, preferences
  382. // will be saved.
  383. //
  384. if (fRememberModes)
  385. {
  386. SaveAllSettings();
  387. }
  388. //
  389. // Show modemenu again; allow appwndproc to process messages
  390. //
  391. if (!bChange)
  392. {
  393. SetTimer(hwnd, TRAY_ID, 10, NULL);
  394. }
  395. Waiting=FALSE;
  396. //
  397. // if Current hasnt changed then we return false
  398. //
  399. return (bChange);
  400. }
  401. //
  402. //********************************************************************
  403. //
  404. // CompareDevmodes ( LPDEVMODEINFO, LPDEVMODEINFO )
  405. //
  406. // Compares 2 devmodes -
  407. // Returns 0 if equal, -1 if first > second, +1 if first < second
  408. //
  409. // msb to lsb: xres, yres, bpp, hertz
  410. //********************************************************************
  411. //
  412. int _cdecl CompareDevmodes( LPDEVMODEINFO pDmi1, LPDEVMODEINFO pDmi2 )
  413. {
  414. INT compare;
  415. LPDEVMODE pDm1 = &(pDmi1->dm);
  416. LPDEVMODE pDm2 = &(pDmi2->dm);
  417. //
  418. // Compare Xs, then Ys, BPP, and Hz. If !fShowFreqs
  419. // then compare only Xs, Ys, and BPP.
  420. //
  421. if ( !fSortByBPP || ((compare= BPP(pDm1) - BPP(pDm2)) == 0))
  422. {
  423. if( (compare= ( XRES(pDm1) - XRES(pDm2) ) ) == 0 )
  424. {
  425. if( (compare= ( YRES(pDm1) - YRES(pDm2) ) ) == 0 )
  426. {
  427. if ( fSortByBPP || ((compare= BPP(pDm1) - BPP(pDm2)) == 0))
  428. {
  429. compare = fShowFreqs ? (HZ(pDm1) - HZ(pDm2)) : 0;
  430. }
  431. }
  432. }
  433. }
  434. //
  435. // Set return value as -1, 0, or 1 only
  436. //
  437. if( compare < 0)
  438. {
  439. compare= -1;
  440. }
  441. else
  442. {
  443. if( compare > 0 )
  444. {
  445. compare= 1;
  446. }
  447. }
  448. return( compare );
  449. }
  450. //
  451. //********************************************************************
  452. //
  453. // CheckMenuItemCurrentMode ( INT )
  454. //
  455. // Traverse all menu items and check the Hz value corresponding
  456. // to the current mode. Also, highlight the current resolution/
  457. // BPP as defaultmenuitem
  458. //
  459. //********************************************************************
  460. //
  461. void CheckMenuItemCurrentMode( INT iDisplay )
  462. {
  463. int i; // counter
  464. DEVMODEINFO dmi; // temporary storage for current DM
  465. LPQRMONITORINFO lpqrmi; // temporary ptr
  466. HMENU hMenu; // Frequency submenu for a given Res/BPP
  467. UINT MenuItem; // Menu item for exact devmode
  468. DWORD dwSta; // returns status variable
  469. lpqrmi = &pMonitors[iDisplay];
  470. //
  471. // Need a pointer to the current devmode. This function will search
  472. // pModes trying to match the devmode pointed to by pCurrentdm.
  473. // After the 1st time through, pCurrentdm will be a ptr IN pModes
  474. //
  475. if (!lpqrmi->pCurrentdm)
  476. {
  477. //
  478. // Get current devmode
  479. //
  480. GetCurrentDevMode(iDisplay, &(dmi.dm));
  481. lpqrmi->pCurrentdm = &dmi;
  482. }
  483. //
  484. // Uncheck all menu items
  485. //
  486. for( i=0; i<lpqrmi->iModes; i++ )
  487. {
  488. hMenu = lpqrmi->FreqMenu[FREQMENU( &lpqrmi->pModes[i] )];
  489. MenuItem= MENUITEM( &lpqrmi->pModes[i] );
  490. //
  491. // Uncheck the Hz in the FreqMenu (if applicable); uncheck item on mode menu
  492. //
  493. if (hMenu)
  494. {
  495. dwSta= CheckMenuItem(hMenu, MenuItem, MF_BYCOMMAND|MF_UNCHECKED);
  496. CheckMenuItem(lpqrmi->ModeMenu, FREQMENU( &lpqrmi->pModes[i] ), MF_BYPOSITION | MF_UNCHECKED );
  497. }
  498. CheckMenuItem(lpqrmi->ModeMenu, MenuItem, MF_BYCOMMAND | MF_UNCHECKED );
  499. }
  500. //
  501. // Check the current one
  502. //
  503. for( i=0; i<lpqrmi->iModes; i++ )
  504. {
  505. //
  506. // Go through the array looking for a match of the current devmode
  507. //
  508. if( ( CompareDevmodes( lpqrmi->pCurrentdm, &lpqrmi->pModes[i] ) ) == 0 )
  509. {
  510. //
  511. // Found it!
  512. // Get the menu item ID for this devmode and which
  513. // frequency submenu it is a part of.
  514. //
  515. hMenu = lpqrmi->FreqMenu[FREQMENU( &lpqrmi->pModes[i] )];
  516. MenuItem= MENUITEM( &lpqrmi->pModes[i] );
  517. //
  518. // Save this ptr in the pCurrentdm variable
  519. // check menu item on mode menu and check mode
  520. // on frequency submenu (if applicable)
  521. //
  522. lpqrmi->pCurrentdm = &lpqrmi->pModes[i];
  523. if (hMenu)
  524. {
  525. dwSta= CheckMenuItem(hMenu, MenuItem, MF_BYCOMMAND|MF_CHECKED);
  526. CheckMenuItem(lpqrmi->ModeMenu, FREQMENU(&lpqrmi->pModes[i]), MF_BYPOSITION | MF_CHECKED );
  527. }
  528. else
  529. {
  530. CheckMenuItem(lpqrmi->ModeMenu, MenuItem, MF_BYCOMMAND | MF_CHECKED );
  531. }
  532. break;
  533. }
  534. }
  535. }
  536. //
  537. //********************************************************************
  538. //
  539. // DestroyModeMenu( INT iDisplay, BOOL bRebuild, BOOL bNeedtoSort )
  540. //
  541. // Free all frequency submenus and the mode menu
  542. //
  543. //********************************************************************
  544. //
  545. void DestroyModeMenu( INT iDisplay, BOOL bRebuild, BOOL bNeedtoSort)
  546. {
  547. int i;
  548. LPQRMONITORINFO lpqrmi; // temporary ptr
  549. lpqrmi = &pMonitors[iDisplay];
  550. //
  551. // Free all frequency submenus
  552. //
  553. for ( i = 0; i < lpqrmi->iModes; i++ )
  554. {
  555. if (IsMenu(lpqrmi->FreqMenu[i]))
  556. {
  557. DestroyMenu( lpqrmi->FreqMenu[i] );
  558. lpqrmi->FreqMenu[i] = NULL;
  559. }
  560. }
  561. //
  562. // Free the mode menu (resolutions/BPP)
  563. //
  564. if (lpqrmi->ModeMenu)
  565. {
  566. DestroyMenu(lpqrmi->ModeMenu);
  567. lpqrmi->ModeMenu = NULL;
  568. if (iMonitors==1)
  569. {
  570. DestroyMenu(MonitorMenu);
  571. MonitorMenu = NULL;
  572. }
  573. }
  574. if (bRebuild)
  575. {
  576. lpqrmi->ModeMenu = GetModeMenu( iDisplay, bNeedtoSort );
  577. if (iMonitors==1)
  578. {
  579. MonitorMenu = lpqrmi->ModeMenu;
  580. AppendMainMenu();
  581. }
  582. else
  583. {
  584. // If ModifyMenu replaces a menu item that opens a drop-down menu or submenu, the
  585. // function destroys the old drop-down menu/submenu & frees the memory used by it.
  586. ModifyMenu( MonitorMenu, iDisplay, MF_BYPOSITION | MF_POPUP, (UINT_PTR)lpqrmi->ModeMenu,
  587. (pMonitors[iDisplay].bPrimary ? pMonitors[iDisplay].PrimaryMonitorName : pMonitors[iDisplay].MonitorName) );
  588. }
  589. }
  590. }
  591. //
  592. //********************************************************************
  593. //
  594. // HandleFreqMenu( )
  595. //
  596. // Either append submenu to res/bpp, save it for later, or
  597. // ditch it and put all Hz entries on mode menu.
  598. // If there is only one Hz for a given Res, we dont need it.
  599. //
  600. //********************************************************************
  601. //
  602. VOID HandleFreqMenu( INT iDisplay, int FreqCount, int ResCounter, int pFirst)
  603. {
  604. PTCHAR Res=NULL;
  605. PTCHAR Hz=NULL;
  606. LPQRMONITORINFO lpqrmi; // temporary ptr
  607. lpqrmi = &pMonitors[iDisplay];
  608. GetModeName(&lpqrmi->pModes[pFirst].dm, &Res, &Hz);
  609. //
  610. // Dont use submenus if there is only 1 Hz
  611. // This is always true when freqmenulocation==IDD_ALLMODEMENU
  612. // OR not showing frequency menus
  613. // Concatenate Res & Hz into one string (IF fShowFreqs)
  614. //
  615. if ( FreqCount == 1 )
  616. {
  617. if (fShowFreqs)
  618. {
  619. PTCHAR ResHz;
  620. if (ResHz=LocalAlloc( LPTR, sizeof(TCHAR)*
  621. (lstrlen(Res)+lstrlen(Hz)+1) ))
  622. {
  623. wsprintf(ResHz,TEXT("%s%s"),Res,Hz);
  624. AppendMenu(lpqrmi->ModeMenu, MF_STRING,
  625. (iDisplay+1)*MENU_RES+pFirst, ResHz);
  626. }
  627. LocalFree(ResHz);
  628. }
  629. else
  630. {
  631. AppendMenu(lpqrmi->ModeMenu, MF_STRING,
  632. (iDisplay+1)*MENU_RES+pFirst, Res);
  633. }
  634. }
  635. else
  636. {
  637. int i=0;
  638. int nAppended=0;
  639. //
  640. // Create Popup and append all Hz strings
  641. // Append FreqCount items, possibly skipping over some modes
  642. //
  643. lpqrmi->FreqMenu[ResCounter] = CreatePopupMenu();
  644. for (i=0; nAppended < FreqCount; i++)
  645. {
  646. PTCHAR LoopRes=NULL;
  647. PTCHAR LoopHz=NULL;
  648. //
  649. // Skip untested modes if requested. FreqCount does NOT
  650. // include skipped modes, so we count up with nAppended, not i.
  651. //
  652. if ( !fShowTestedModes || fGoodMode(&lpqrmi->pModes[pFirst+i]) )
  653. {
  654. GetModeName(&lpqrmi->pModes[pFirst+i].dm,&LoopRes,&LoopHz);
  655. AppendMenu(lpqrmi->FreqMenu[ResCounter],MF_STRING,
  656. (iDisplay+1)*MENU_RES+pFirst+i,LoopHz);
  657. nAppended++;
  658. LocalFree(LoopRes);
  659. LocalFree(LoopHz);
  660. LoopRes=NULL;
  661. LoopHz=NULL;
  662. }
  663. }
  664. //
  665. // Hang menu off side of each bpp/res
  666. //
  667. if (FreqMenuLocation == IDD_SUBMENUS)
  668. {
  669. AppendMenu(lpqrmi->ModeMenu,MF_POPUP,
  670. (UINT_PTR)lpqrmi->FreqMenu[ResCounter],Res);
  671. }
  672. else
  673. {
  674. //
  675. // Only show submenu for the current mode
  676. // Use BESTHZ mode or the VALID mode with the
  677. // lowest frequency.
  678. //
  679. if ( (FreqMenuLocation == IDD_ONEMENUMOBILE) ||
  680. (FreqMenuLocation == IDD_ONEMENUBOTTOM) )
  681. {
  682. int BestHz=0;
  683. int index;
  684. //
  685. // Start with highest freq (pFirst+i-1)
  686. // and work down to pFirst looking for BestHz.
  687. // if we find BESTHZ use that one, else
  688. // use last VALIDMODE we get before loop ends
  689. //
  690. for (index=pFirst+i-1 ; index >= pFirst; index--)
  691. {
  692. if ( VALIDMODE(&lpqrmi->pModes[index]) == MODE_BESTHZ )
  693. {
  694. BestHz = index;
  695. break;
  696. }
  697. else
  698. {
  699. if (VALIDMODE(&lpqrmi->pModes[index])!=MODE_INVALID)
  700. {
  701. BestHz = index;
  702. }
  703. }
  704. }
  705. //
  706. // No valid/besthz modes. Use smallest Hz for that Res
  707. //
  708. if (!BestHz)
  709. {
  710. BestHz = pFirst;
  711. }
  712. AppendMenu(lpqrmi->ModeMenu,MF_STRING,
  713. (iDisplay+1)*MENU_RES+BestHz,Res);
  714. }
  715. }
  716. }
  717. LocalFree(Res);
  718. LocalFree(Hz);
  719. }
  720. //
  721. //********************************************************************
  722. //
  723. // GetModeMenu( INT, BOOL )
  724. //
  725. // Build the mode menu with each resolution/BPP having a
  726. // pointer to its own frequency submenu
  727. //
  728. //********************************************************************
  729. //
  730. HMENU GetModeMenu ( INT iDisplay, BOOL bNeedtoSort )
  731. {
  732. int n; // counter
  733. BOOL bMajorChange=FALSE; // change in the major sort order field
  734. BOOL bMinorChange=FALSE; // change in the minor sort order field
  735. int FreqCount=0; // number of freqs on the current submenu
  736. int ResCounter=0; // Res/Color defines the freqmenu #
  737. INT FirstMode=-1; // index in pmodes; 1st mode for given res/bpp
  738. LPQRMONITORINFO lpqrmi; // temporary ptr
  739. lpqrmi = &pMonitors[iDisplay];
  740. if (!lpqrmi->ModeMenu)
  741. {
  742. lpqrmi->ModeMenu = CreatePopupMenu();
  743. if (bNeedtoSort)
  744. {
  745. qsort( (void*) lpqrmi->pModes,
  746. (size_t) lpqrmi->iModes,
  747. (size_t) sizeof(DEVMODEINFO),
  748. ( int (_cdecl*)(const void*,const void*) ) CompareDevmodes );
  749. lpqrmi->pCurrentdm = NULL;
  750. }
  751. //
  752. // For each devmode, add res/color to menu.
  753. // Make a submenu of frequencies for each res/color
  754. //
  755. for (n=0; n < lpqrmi->iModes; n++)
  756. {
  757. LPDEVMODEINFO pDM = &lpqrmi->pModes[n];
  758. //
  759. // Tested successfully or might require restart
  760. //
  761. if ( ( (CDSTEST(pDM) == DISP_CHANGE_SUCCESSFUL) ||
  762. (fShowModesThatNeedRestart && (CDSTEST(pDM) == DISP_CHANGE_RESTART)) ) &&
  763. ( !fShowTestedModes || fGoodMode(pDM) ) )
  764. {
  765. //
  766. // Check for change in the major/minor sort item
  767. // *only after we 'initialize' firstmode below
  768. //
  769. if (FirstMode == -1)
  770. {
  771. //
  772. // First time thru, initialize FirstMode,counter
  773. //
  774. FirstMode = n;
  775. FreqCount=0;
  776. }
  777. else
  778. {
  779. if( BPP(&lpqrmi->pModes[FirstMode].dm) != BPP(&pDM->dm) )
  780. {
  781. bMajorChange = fSortByBPP;
  782. bMinorChange = !fSortByBPP;
  783. }
  784. if( ( XRES(&lpqrmi->pModes[FirstMode].dm) != XRES(&pDM->dm) ) ||
  785. ( YRES(&lpqrmi->pModes[FirstMode].dm) != YRES(&pDM->dm) ) )
  786. {
  787. bMajorChange |= !fSortByBPP;
  788. bMinorChange |= fSortByBPP;
  789. }
  790. //
  791. // The BPP and/or the Resolution changed.
  792. //
  793. if ( bMajorChange || bMinorChange )
  794. {
  795. //
  796. // Appends a Res/BPP and a submenu if applicable
  797. //
  798. HandleFreqMenu(iDisplay,FreqCount,ResCounter,FirstMode);
  799. ResCounter++;
  800. //
  801. // Need a separator when major sort item changes
  802. //
  803. if ( bMajorChange )
  804. {
  805. AppendMenu(lpqrmi->ModeMenu,MF_SEPARATOR,0,NULL);
  806. ResCounter++;
  807. }
  808. //
  809. // n is first mode for the new res/bpp
  810. // reset counter, flags
  811. //
  812. FirstMode = n;
  813. FreqCount= 0;
  814. bMajorChange = FALSE;
  815. bMinorChange = FALSE;
  816. }
  817. }
  818. //
  819. // Fill in fields for this mode; inc freqcount
  820. //
  821. MENUITEM( pDM ) = (iDisplay+1)*MENU_RES+n;
  822. FREQMENU( pDM ) = ResCounter;
  823. FreqCount++;
  824. //
  825. // ALLMODEMENU - Force menu append every time
  826. //
  827. if (FreqMenuLocation == IDD_ALLMODEMENU)
  828. {
  829. bMinorChange = TRUE;
  830. }
  831. }
  832. } // end for
  833. //
  834. // NO VALID MODES!!! Certainly the current mode should be valid. Make
  835. // this mode VALID. Setup FreqCount, FirstMode for the last HandleFreqMenu
  836. //
  837. if (FirstMode == -1)
  838. {
  839. DEVMODEINFO DisplayModeInfo;
  840. DisplayModeInfo.dm.dmSize= sizeof(DEVMODE);
  841. GetCurrentDevMode(iDisplay, &DisplayModeInfo.dm);
  842. for (n=0;
  843. CompareDevmodes(&DisplayModeInfo,&lpqrmi->pModes[n]) != 0;
  844. n++ )
  845. {
  846. }
  847. VALIDMODE(&lpqrmi->pModes[n]) = MODE_BESTHZ;
  848. FirstMode = n;
  849. FreqCount = 1;
  850. }
  851. //
  852. // Handle the FreqMenu for the last Res/BPP.
  853. //
  854. HandleFreqMenu(iDisplay,FreqCount,ResCounter,FirstMode);
  855. //
  856. // Update menu checks; mode status
  857. //
  858. CheckMenuItemCurrentMode( iDisplay );
  859. //
  860. // Put Hz menu next to current mode, or at the bottom
  861. //
  862. if (FreqMenuLocation == IDD_ONEMENUMOBILE)
  863. {
  864. MENUITEMINFO mii;
  865. ZeroMemory(&mii, sizeof(mii));
  866. mii.cbSize = sizeof(mii);
  867. mii.fMask = MIIM_SUBMENU;
  868. mii.hSubMenu = lpqrmi->FreqMenu[FREQMENU(lpqrmi->pCurrentdm)];
  869. SetMenuItemInfo(lpqrmi->ModeMenu, FREQMENU(lpqrmi->pCurrentdm), MF_BYPOSITION, &mii);
  870. }
  871. else
  872. {
  873. if (FreqMenuLocation == IDD_ONEMENUBOTTOM)
  874. {
  875. PTCHAR szRefRate;
  876. UINT flags=MF_POPUP;
  877. szRefRate = GetResourceString(IDS_REFRESHRATE);
  878. if ( !lpqrmi->FreqMenu[FREQMENU(lpqrmi->pCurrentdm)] )
  879. {
  880. flags = MF_GRAYED;
  881. }
  882. AppendMenu(lpqrmi->ModeMenu,MF_SEPARATOR,0,NULL);
  883. AppendMenu(lpqrmi->ModeMenu, flags,
  884. (UINT_PTR)lpqrmi->FreqMenu[FREQMENU(lpqrmi->pCurrentdm)],
  885. szRefRate);
  886. LocalFree(szRefRate);
  887. }
  888. }
  889. }
  890. return (lpqrmi->ModeMenu);
  891. }
  892. //
  893. //********************************************************************
  894. //
  895. // AppendMainMenu( VOID )
  896. //
  897. // Append main menu (from .rc file) to monitor menu
  898. //
  899. //********************************************************************
  900. //
  901. VOID AppendMainMenu()
  902. {
  903. #ifdef MAINWITHMODE
  904. int n; // counter
  905. //
  906. // Add main menu to bottom of mode menu. These menu
  907. // items come from MainMenu as defined in .rc file
  908. //
  909. AppendMenu(MonitorMenu,MF_SEPARATOR,0,NULL);
  910. for (n=0; n < GetMenuItemCount(MainMenu); n++)
  911. {
  912. MENUITEMINFO mii;
  913. //
  914. // Set up mii struct to retrieve the length of
  915. // each menu item string via GetMenuItemInfo().
  916. //
  917. ZeroMemory(&mii, sizeof(mii));
  918. mii.cbSize = sizeof(mii);
  919. mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID;
  920. mii.cch = GetMenuString(MainMenu, n, NULL, 0, MF_BYPOSITION) +1;
  921. //
  922. // Allocate enough memory and read in the string.
  923. //
  924. if (mii.dwTypeData = LocalAlloc( LPTR, mii.cch*sizeof(TCHAR) ))
  925. {
  926. //
  927. // Read in the string, get it's ID and append to the menu
  928. //
  929. if (GetMenuString(MainMenu, n, mii.dwTypeData, mii.cch,MF_BYPOSITION))
  930. {
  931. mii.wID=GetMenuItemID(MainMenu, n);
  932. AppendMenu(MonitorMenu, MF_STRING, mii.wID, mii.dwTypeData);
  933. }
  934. LocalFree(mii.dwTypeData);
  935. }
  936. }
  937. SetMenuDefaultItem(MonitorMenu,MENU_PROPERTIES,MF_BYCOMMAND);
  938. #endif
  939. }
  940. //
  941. //********************************************************************
  942. //
  943. // GetMonitorMenu( BOOL )
  944. //
  945. // Build all mode menus with each resolution/BPP having a
  946. // pointer to its own frequency submenu
  947. //
  948. //********************************************************************
  949. //
  950. HMENU GetMonitorMenu ( BOOL bNeedtoSort )
  951. {
  952. if (!MonitorMenu)
  953. {
  954. //
  955. // Use Modemenu of iDisplay==0 as the monitor menu
  956. //
  957. if (iMonitors == 1)
  958. {
  959. MonitorMenu = GetModeMenu(0, bNeedtoSort);
  960. }
  961. else
  962. {
  963. INT iDisplay;
  964. MonitorMenu = CreatePopupMenu();
  965. for (iDisplay=0; iDisplay < iMonitors; iDisplay++)
  966. {
  967. //
  968. // append each monitor name to the main monitor menu
  969. //
  970. AppendMenu( MonitorMenu, MF_POPUP,
  971. (UINT_PTR)GetModeMenu(iDisplay, bNeedtoSort),
  972. (pMonitors[iDisplay].bPrimary ? pMonitors[iDisplay].PrimaryMonitorName : pMonitors[iDisplay].MonitorName) );
  973. }
  974. }
  975. AppendMainMenu();
  976. }
  977. return MonitorMenu;
  978. }
  979. //
  980. //********************************************************************
  981. //
  982. // SetMonitorDeviceInfo( BOOL bFirstTime )
  983. //
  984. // Set monitor info fields : primary? attached?
  985. // and the correct monitor name, based on bPrimary
  986. //
  987. //********************************************************************
  988. //
  989. BOOL SetMonitorDeviceInfo( BOOL bFirstTime )
  990. {
  991. BOOL bFoundPrimary=FALSE;
  992. BOOL bChange=FALSE;
  993. PTCHAR szMonitorRes;
  994. int iDisplay;
  995. int n;
  996. DISPLAY_DEVICE DispDev;
  997. if ( (iMonitors > 1) && (lpfnEDD) )
  998. {
  999. szMonitorRes = GetResourceString(IDS_MONITOR);
  1000. DispDev.cb = sizeof(DispDev);
  1001. iDisplay=0;
  1002. for ( n=0; (lpfnEDD)(NULL, n, &DispDev, 0); n++ )
  1003. {
  1004. if ( !(DispDev.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) )
  1005. {
  1006. DWORD dwSize;
  1007. TCHAR index[8];
  1008. //
  1009. // For each display, get the monitor name, primary monitor name, & Device name
  1010. // Alloc enough memory for MonitorName string to have up to 3 digits for the monitor index.
  1011. //
  1012. if (DispDev.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
  1013. {
  1014. bChange |= (pMonitors[iDisplay].bPrimary != TRUE);
  1015. pMonitors[iDisplay].bPrimary = TRUE;
  1016. bFoundPrimary=TRUE;
  1017. }
  1018. else
  1019. {
  1020. bChange |= (pMonitors[iDisplay].bPrimary != FALSE);
  1021. pMonitors[iDisplay].bPrimary = FALSE;
  1022. }
  1023. //
  1024. // Allocation sizes, device name, and primarymonitorname all never change
  1025. //
  1026. if (bFirstTime)
  1027. {
  1028. pMonitors[iDisplay].DeviceName = GlobalAlloc(GPTR, sizeof(TCHAR)*(lstrlen(DispDev.DeviceName)+1));
  1029. pMonitors[iDisplay].MonitorName = GlobalAlloc( GPTR, sizeof(TCHAR)*dwSize );
  1030. pMonitors[iDisplay].PrimaryMonitorName = GlobalAlloc( GPTR, sizeof(TCHAR)*dwSize );
  1031. }
  1032. // Memory allocation failed we can't continue
  1033. if (!pMonitors[iDisplay].DeviceName ||
  1034. !pMonitors[iDisplay].MonitorName ||
  1035. !pMonitors[iDisplay].PrimaryMonitorName)
  1036. return FALSE;
  1037. if (bFirstTime)
  1038. {
  1039. lstrcpy(pMonitors[iDisplay].DeviceName, DispDev.DeviceName);
  1040. dwSize = lstrlen(DispDev.DeviceString) + lstrlen(szMonitorRes);
  1041. dwSize += lstrlen(TEXT("Primary"));
  1042. wsprintf( pMonitors[iDisplay].PrimaryMonitorName, szMonitorRes,
  1043. TEXT("Primary "), TEXT(""), DispDev.DeviceString );
  1044. bChange = TRUE;
  1045. }
  1046. // this ensures we always have primary, 2,3,4, etc. (never a monitor 0 or 1)
  1047. //
  1048. _itot( (iDisplay + (bFoundPrimary ? 1 : 2)),index,8);
  1049. lstrcat(index,TEXT(" "));
  1050. wsprintf( pMonitors[iDisplay].MonitorName, szMonitorRes,
  1051. TEXT(""), index, DispDev.DeviceString);
  1052. bChange |= (pMonitors[iDisplay].bAttached != (BOOL)(DispDev.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP));
  1053. pMonitors[iDisplay].bAttached = (DispDev.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP);
  1054. iDisplay++;
  1055. }
  1056. DispDev.cb = sizeof(DispDev); // always reset before next call to be safe
  1057. }
  1058. LocalFree(szMonitorRes);
  1059. if (!bFirstTime)
  1060. {
  1061. for (n=0; n< iMonitors; n++)
  1062. {
  1063. ModifyMenu( MonitorMenu, n, MF_BYPOSITION | MF_POPUP, (UINT_PTR)pMonitors[n].ModeMenu,
  1064. (pMonitors[n].bPrimary ? pMonitors[n].PrimaryMonitorName : pMonitors[n].MonitorName));
  1065. }
  1066. }
  1067. }
  1068. return bChange;
  1069. }
  1070. //
  1071. //********************************************************************
  1072. //
  1073. // BuildMonitorArray( )
  1074. //
  1075. // Allocate & fill in a monitorinfo struct for each display device
  1076. //
  1077. //********************************************************************
  1078. //
  1079. BOOL BuildMonitorArray( )
  1080. {
  1081. int iDisplay;
  1082. DISPLAY_DEVICE DispDev;
  1083. //
  1084. // Find the number of monitors/displaydevices
  1085. // alloc a monitorinfo struct per monitor
  1086. //
  1087. iMonitors = 1;
  1088. // getSysMet != EnumDispDevices!!! (netmtg, etc.)
  1089. // iMonitors = max(GetSystemMetrics(SM_CMONITORS),1);
  1090. //
  1091. // EDSEx is win98 & NT5 only -- the ones with multimonitor, the check for EDD is just to
  1092. // check that we have the api we're going to call. win95 osr2.5/NT4 are single-mon only
  1093. //
  1094. if (lpfnEDSEx && lpfnEDD)
  1095. {
  1096. DispDev.cb = sizeof(DispDev);
  1097. iMonitors=0;
  1098. for (iDisplay=0; (lpfnEDD)(NULL, iDisplay, &DispDev, 0); iDisplay++)
  1099. {
  1100. if ( !(DispDev.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) )
  1101. {
  1102. iMonitors++;
  1103. }
  1104. }
  1105. }
  1106. pMonitors = GlobalAlloc(GPTR, iMonitors*sizeof(QRMONITORINFO));
  1107. if (pMonitors)
  1108. {
  1109. //
  1110. // On a multimon system, get the display device info --
  1111. // monitor and device names + primary? and attached?
  1112. //
  1113. if ( (iMonitors > 1) && (lpfnEDD) )
  1114. {
  1115. SetMonitorDeviceInfo( TRUE );
  1116. }
  1117. else
  1118. {
  1119. pMonitors[0].DeviceName = NULL;
  1120. pMonitors[0].MonitorName = NULL;
  1121. pMonitors[0].PrimaryMonitorName = NULL;
  1122. }
  1123. }
  1124. else
  1125. {
  1126. iMonitors = 0;
  1127. }
  1128. return pMonitors != NULL;
  1129. }
  1130. //
  1131. //********************************************************************
  1132. //
  1133. // BuildDevmodeLists( )
  1134. //
  1135. // Enumerate all devmodes for each display device into an array.
  1136. // Sort them, remove duplicates, and filter out 4bpp modes
  1137. // Create a popup menu for each display device (put all modes
  1138. // on the main menu if it is a single monitor machine)
  1139. //
  1140. //********************************************************************
  1141. //
  1142. BOOL BuildDevmodeLists( )
  1143. {
  1144. DEVMODE DisplayMode; // temporary devmode storage
  1145. BOOL bShrink=FALSE; // set if iModes ever decreases
  1146. int nModes,
  1147. n,
  1148. iDisplay; // counters
  1149. LPDEVMODEINFO lpdm;
  1150. LPQRMONITORINFO lpqrmi;
  1151. DisplayMode.dmSize= sizeof(DEVMODE);
  1152. //
  1153. // Fill in each display's/monitor's mode list
  1154. //
  1155. for (iDisplay=0; iDisplay < iMonitors; iDisplay++)
  1156. {
  1157. DWORD dwFlags = 0;
  1158. lpqrmi = &pMonitors[iDisplay];
  1159. lpqrmi->ModeMenu = NULL;
  1160. lpqrmi->FreqMenu = NULL;
  1161. lpqrmi->iModes = 0;
  1162. lpqrmi->pModes = NULL;
  1163. lpqrmi->pCurrentdm = NULL;
  1164. //
  1165. // Find the number of modes known by driver for each monitor
  1166. //
  1167. if (lpfnEDSEx)
  1168. {
  1169. for( nModes=0; (lpfnEDSEx)(pMonitors[iDisplay].DeviceName, nModes, &DisplayMode, dwFlags); nModes++)
  1170. ;
  1171. }
  1172. else
  1173. {
  1174. for( nModes=0; EnumDisplaySettings(pMonitors[iDisplay].DeviceName, nModes, &DisplayMode); nModes++)
  1175. ;
  1176. }
  1177. //
  1178. // Get space for all modes
  1179. //
  1180. lpqrmi->pModes = (LPDEVMODEINFO) GlobalAlloc( GPTR, nModes*sizeof(DEVMODEINFO) );
  1181. lpdm = lpqrmi->pModes;
  1182. if( !lpdm )
  1183. {
  1184. DestroyModeMenu( iDisplay, FALSE, FALSE );
  1185. return FALSE;
  1186. }
  1187. //
  1188. // Get all display modes into the pModes array
  1189. //
  1190. for( n=0; n<nModes; n++ )
  1191. {
  1192. lpdm[n].dm.dmSize= sizeof(DEVMODE);
  1193. //
  1194. // Get next mode into next spot in pModes
  1195. //
  1196. if (lpfnEDSEx)
  1197. {
  1198. (lpfnEDSEx)(pMonitors[iDisplay].DeviceName, n, &lpdm[n].dm, dwFlags );
  1199. }
  1200. else
  1201. {
  1202. EnumDisplaySettings(pMonitors[iDisplay].DeviceName, n, &lpdm[n].dm );
  1203. }
  1204. //
  1205. // If any Hz is NOT 0 or 1 (default), then turn on Freq flag.
  1206. // This will be true on NT. Win95 will always return 0 or 1.
  1207. //
  1208. if ( HZ(&lpdm[n].dm) && (HZ(&lpdm[n].dm) != 1) )
  1209. QuickResFlags |= QF_SHOWFREQS;
  1210. }
  1211. //
  1212. // sort them according to QF_SORTBYBPP :
  1213. // (1) BPP X Y HZ or (2) X Y BPP HZ
  1214. //
  1215. qsort( (void*) lpdm,
  1216. (size_t) nModes,
  1217. (size_t) sizeof(DEVMODEINFO),
  1218. ( int (_cdecl*)(const void*,const void*) ) CompareDevmodes );
  1219. //
  1220. // Filter out any duplicate devmodes return by the driver
  1221. // and any modes with x resolution < 640 pixels. We dont
  1222. // want to show ModeX modes (320x200, 320x240, etc.)
  1223. //
  1224. if (nModes > 1 )
  1225. {
  1226. for (n=0; n+1 < nModes; )
  1227. {
  1228. if (XRES(&lpdm[n].dm) < 640)
  1229. {
  1230. nModes--;
  1231. bShrink = TRUE;
  1232. MoveMemory( &lpdm[n],
  1233. &lpdm[n+1],
  1234. (nModes-n)*sizeof(DEVMODEINFO) );
  1235. }
  1236. else
  1237. {
  1238. //
  1239. // If consecutive devmodes are identical, then copy the next
  1240. // one over the dup and decrement iModes (# of devmodes).
  1241. //
  1242. while ( CompareDevmodes(&lpdm[n],&lpdm[n+1]) == 0 )
  1243. {
  1244. //
  1245. // Don't go past the last devmode
  1246. //
  1247. if (n+2 < nModes--)
  1248. {
  1249. bShrink = TRUE;
  1250. MoveMemory( &lpdm[n],
  1251. &lpdm[n+1],
  1252. (nModes-n)*sizeof(DEVMODEINFO) );
  1253. }
  1254. else
  1255. {
  1256. break;
  1257. }
  1258. }
  1259. n++;
  1260. }
  1261. }
  1262. }
  1263. //
  1264. // Check CDS return value for all modes and eliminate all 4bpp
  1265. // modes that have a corresponding 8bpp mode at the same res
  1266. //
  1267. for (n=0; n < nModes; n++)
  1268. {
  1269. CDSTEST(&lpdm[n]) = (WORD)ChangeDisplaySettingsEx( lpqrmi->DeviceName, &lpdm[n].dm,
  1270. NULL, CDS_TEST, 0);
  1271. //
  1272. // Filter out all 4BPP modes that have an 8BPP mode at the same resolution
  1273. //
  1274. if (BPP(&lpdm[n].dm)==8)
  1275. {
  1276. INT i;
  1277. for (i=0; i < n; )
  1278. {
  1279. if ( (BPP (&lpdm[i].dm) == 4) &&
  1280. (XRES(&lpdm[n].dm) == XRES(&lpdm[i].dm)) &&
  1281. (YRES(&lpdm[n].dm) == YRES(&lpdm[i].dm)) )
  1282. {
  1283. nModes--;
  1284. bShrink = TRUE;
  1285. MoveMemory( &lpdm[i],
  1286. &lpdm[i+1],
  1287. (nModes-i)*sizeof(DEVMODEINFO) );
  1288. n--;
  1289. }
  1290. else
  1291. {
  1292. i++;
  1293. }
  1294. }
  1295. }
  1296. }
  1297. //
  1298. // nModes might have decreased; might as well free up some memory.
  1299. // Note that iModes could NOT have increased, so the ReAlloc will be okay.
  1300. //
  1301. if (bShrink)
  1302. {
  1303. lpqrmi->pModes = (LPDEVMODEINFO) GlobalReAlloc(lpqrmi->pModes,
  1304. nModes*sizeof(DEVMODEINFO),
  1305. GMEM_MOVEABLE );
  1306. }
  1307. lpqrmi->iModes = nModes;
  1308. //
  1309. // At most, we need 1 freqmenu per mode (actually it's always < #modes.)
  1310. // Note : separators take up 1 (unused) hmenu in the array, so it would
  1311. // that we need hmenus > #modes, when "all modes on main menu". But,
  1312. // in that case, we dont use the freq submenus at all. :)
  1313. //
  1314. lpqrmi->FreqMenu = (HMENU*) GlobalAlloc(GPTR,nModes*sizeof(HMENU));
  1315. for (n=0; n < nModes; n++)
  1316. {
  1317. lpqrmi->FreqMenu[n] = NULL;
  1318. }
  1319. //
  1320. // Get modeflags from registry or zero out modeflags[]
  1321. //
  1322. GetDevmodeFlags(iDisplay);
  1323. //
  1324. // Call GetModeMenu to put all strings/popups in place
  1325. // Current mode will be the best until user changes it.
  1326. //
  1327. GetModeMenu( iDisplay, FALSE );
  1328. VALIDMODE(lpqrmi->pCurrentdm) = MODE_BESTHZ;
  1329. }
  1330. return TRUE;
  1331. }
  1332. //
  1333. //********************************************************************
  1334. //
  1335. // DestroyDevmodeLists( )
  1336. //
  1337. // free all the memory allocated for modes and menus for each device
  1338. //
  1339. //********************************************************************
  1340. //
  1341. BOOL DestroyDevmodeLists()
  1342. {
  1343. int iDisplay;
  1344. LPQRMONITORINFO lpqrmi;
  1345. for (iDisplay=0; iDisplay < iMonitors; iDisplay++)
  1346. {
  1347. lpqrmi = &pMonitors[iDisplay];
  1348. //
  1349. // DestroyModeMenu has freed all the individual menus in this array for us
  1350. //
  1351. if (lpqrmi->FreqMenu)
  1352. {
  1353. GlobalFree(lpqrmi->FreqMenu);
  1354. lpqrmi->FreqMenu = NULL;
  1355. }
  1356. if (lpqrmi->pModes)
  1357. {
  1358. GlobalFree(lpqrmi->pModes);
  1359. lpqrmi->pModes = NULL;
  1360. }
  1361. lpqrmi->iModes = 0;
  1362. lpqrmi->pCurrentdm = NULL;
  1363. }
  1364. return TRUE;
  1365. }
  1366. //
  1367. //********************************************************************
  1368. //
  1369. // DoProperties( )
  1370. //
  1371. // Calls the control panel applet to show 'Display Properties'
  1372. // specifically the display settings
  1373. //
  1374. //********************************************************************
  1375. //
  1376. void DoProperties( )
  1377. {
  1378. STARTUPINFO si;
  1379. PROCESS_INFORMATION pi;
  1380. TCHAR lpszProperties[64] = DISPLAYPROPERTIES;
  1381. GetStartupInfo( &si );
  1382. //
  1383. // Start it up.
  1384. //
  1385. if (CreateProcess(NULL, lpszProperties, NULL, NULL, FALSE,
  1386. 0, NULL, NULL, &si, &pi))
  1387. {
  1388. //
  1389. // Dont care what wait return value is, but we want
  1390. // to 'disable' tray icon for a minute or until the
  1391. // user kills desk.cpl
  1392. //
  1393. WaitForSingleObject( pi.hProcess, 60*1000 );
  1394. CloseHandle ( pi.hThread );
  1395. CloseHandle ( pi.hProcess );
  1396. }
  1397. }
  1398. //
  1399. //********************************************************************
  1400. //
  1401. // AppWndProc(HWND, UINT, WPARAM, LPARAM)
  1402. //
  1403. // Main window proc to process messages
  1404. //
  1405. //********************************************************************
  1406. //
  1407. LRESULT CALLBACK AppWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  1408. {
  1409. POINT pt; // Get cursor pos for the menu placement
  1410. INT i;
  1411. switch (msg)
  1412. {
  1413. case WM_CREATE:
  1414. //
  1415. // Add icon to tray next to time
  1416. //
  1417. TrayMessage(hwnd, NIM_ADD, TRAY_ID, AppIcon);
  1418. break;
  1419. case WM_DESTROY:
  1420. //
  1421. // Remove icon from tray.
  1422. //
  1423. TrayMessage(hwnd, NIM_DELETE, TRAY_ID, NULL );
  1424. PostQuitMessage(0);
  1425. break;
  1426. case WM_DISPLAYCHANGE:
  1427. //
  1428. // New settings. Reset pCurrentdm as index in pModes
  1429. // No need to destroy/rebuild the mode menu, but bPrimary,
  1430. // bAttached may have changed.
  1431. //
  1432. // The Waiting flag makes this a no-op, when its a qres-initiated change
  1433. //
  1434. if (!Waiting)
  1435. {
  1436. for (i=0; i<iMonitors; i++)
  1437. {
  1438. pMonitors[i].pCurrentdm = NULL;
  1439. CheckMenuItemCurrentMode(i);
  1440. }
  1441. SetMonitorDeviceInfo( FALSE );
  1442. }
  1443. break;
  1444. #if 0
  1445. hard to understand when and why we get this message. better leave it alone
  1446. case WM_DEVICECHANGE:
  1447. if (wParam == DBT_CONFIGCHANGED ||
  1448. wParam == DBT_MONITORCHANGE)
  1449. {
  1450. for (i=0; i<iMonitors; i++)
  1451. {
  1452. DestroyModeMenu( i, FALSE, FALSE );
  1453. SetDevmodeFlags( i, TRUE );
  1454. }
  1455. if (MonitorMenu)
  1456. {
  1457. DestroyMenu(MonitorMenu);
  1458. MonitorMenu = NULL;
  1459. }
  1460. DestroyDevmodeLists();
  1461. BuildDevmodeLists();
  1462. MonitorMenu = GetMonitorMenu( TRUE );
  1463. }
  1464. break;
  1465. #endif
  1466. case WM_COMMAND:
  1467. {
  1468. switch (LOWORD(wParam))
  1469. {
  1470. case MENU_CLOSE:
  1471. PostMessage(hwnd, WM_CLOSE, 0, 0);
  1472. break;
  1473. case MENU_PROPERTIES:
  1474. //
  1475. // Start control panel applet
  1476. //
  1477. DoProperties();
  1478. break;
  1479. case MENU_ABOUT:
  1480. //
  1481. // Show a generic about box
  1482. //
  1483. MsgBox(IDS_ABOUT, 0, MB_OK );
  1484. break;
  1485. case MENU_OPTIONS:
  1486. //
  1487. // After showing options dlg box, show mode menu again
  1488. //
  1489. if (fShowFreqs)
  1490. DialogBox(hInstApp, MAKEINTRESOURCE(NTOptions), NULL, NTOptionsDlgProc);
  1491. else
  1492. DialogBox(hInstApp, MAKEINTRESOURCE(W95Options),NULL, W95OptionsDlgProc);
  1493. SetTimer(hwnd, TRAY_ID, 10, NULL);
  1494. break;
  1495. default:
  1496. {
  1497. //
  1498. // Change devmode to pModes[OffsetPdev]
  1499. //
  1500. INT OffsetPdev;
  1501. INT iDisplay;
  1502. //
  1503. // The menu item is an offset from MENU_RES
  1504. // of the selected item.
  1505. //
  1506. iDisplay = LOWORD(wParam) / MENU_RES - 1;
  1507. OffsetPdev = LOWORD(wParam) % MENU_RES;
  1508. //
  1509. // Check that the offset is within range
  1510. //
  1511. if( OffsetPdev >= 0 && OffsetPdev < pMonitors[iDisplay].iModes )
  1512. {
  1513. //
  1514. // if different from current devmode then change it
  1515. //
  1516. if ( CompareDevmodes( &pMonitors[iDisplay].pModes[OffsetPdev],
  1517. pMonitors[iDisplay].pCurrentdm) )
  1518. {
  1519. SetMode(hwnd, iDisplay, OffsetPdev);
  1520. }
  1521. }
  1522. }
  1523. break;
  1524. }
  1525. break;
  1526. }
  1527. case WM_TIMER:
  1528. //
  1529. // Left click was not a double-click
  1530. //
  1531. KillTimer(hwnd, TRAY_ID);
  1532. GetCursorPos(&pt);
  1533. SetForegroundWindow(hwnd);
  1534. //
  1535. // Create and/or Get resolutions menu
  1536. //
  1537. TrackPopupMenu(GetMonitorMenu( FALSE ), TPM_LEFTBUTTON,
  1538. pt.x, pt.y, 0, hwnd, NULL);
  1539. break;
  1540. case TRAY_MSG:
  1541. {
  1542. //
  1543. // No messages processed while waiting on
  1544. // a dlg/msg box to return
  1545. //
  1546. if (!Waiting)
  1547. {
  1548. switch (lParam)
  1549. {
  1550. case WM_RBUTTONUP:
  1551. //
  1552. // Properties, about, Exit
  1553. //
  1554. SetForegroundWindow(hwnd);
  1555. GetCursorPos(&pt);
  1556. TrackPopupMenu(MainMenu, TPM_RIGHTBUTTON,
  1557. pt.x, pt.y, 0, hwnd, NULL);
  1558. break;
  1559. case WM_LBUTTONDOWN:
  1560. //
  1561. // Resolutions menu
  1562. //
  1563. SetTimer(hwnd, TRAY_ID, GetDoubleClickTime()+10, NULL);
  1564. break;
  1565. case WM_LBUTTONDBLCLK:
  1566. //
  1567. // start control panel applet
  1568. //
  1569. KillTimer(hwnd, TRAY_ID);
  1570. DoProperties();
  1571. break;
  1572. }
  1573. }
  1574. }
  1575. break;
  1576. }
  1577. return DefWindowProc(hwnd,msg,wParam,lParam);
  1578. }
  1579. //
  1580. //********************************************************************
  1581. //
  1582. // MsgBox(int, UINT, UINT)
  1583. //
  1584. // Generic messagebox function that can print a value into
  1585. // a format string
  1586. //
  1587. //********************************************************************
  1588. //
  1589. int MsgBox(int id, UINT value, UINT flags)
  1590. {
  1591. PTCHAR msgboxtext=NULL; // message box body text
  1592. INT ret = 0;
  1593. MSGBOXPARAMS mb;
  1594. //
  1595. // Ignore tray clicks while msgbox is up, and
  1596. // Show at least an OK button.
  1597. //
  1598. Waiting = TRUE;
  1599. if (flags == 0)
  1600. {
  1601. flags = MB_OK | MB_USERICON;
  1602. }
  1603. //
  1604. // Can print a value into a format string, if value!=0.
  1605. //
  1606. if (value)
  1607. {
  1608. PTCHAR msgboxfmt; // body test format
  1609. if (msgboxfmt = GetResourceString ( id ))
  1610. {
  1611. if (msgboxtext = LocalAlloc ( LPTR, sizeof(TCHAR)*
  1612. (lstrlen(msgboxfmt)+INT_FORMAT_TO_5_DIGITS+1)))
  1613. {
  1614. wsprintf(msgboxtext,msgboxfmt,value);
  1615. }
  1616. LocalFree( msgboxfmt );
  1617. }
  1618. }
  1619. else
  1620. {
  1621. msgboxtext = GetResourceString ( id );
  1622. }
  1623. if (msgboxtext)
  1624. {
  1625. mb.cbSize = sizeof(mb);
  1626. mb.hwndOwner = NULL;
  1627. mb.hInstance = hInstApp;
  1628. mb.lpszText = msgboxtext;
  1629. mb.lpszCaption = szAppName;
  1630. mb.dwStyle = flags;
  1631. mb.lpszIcon = szAppName;
  1632. mb.dwContextHelpId = 0;
  1633. mb.lpfnMsgBoxCallback = NULL;
  1634. mb.dwLanguageId = MAKELANGID (LANG_NEUTRAL, SUBLANG_NEUTRAL);;
  1635. //
  1636. // Special API for the about box. otherwise, use Messageboxindirect
  1637. //
  1638. if (id == IDS_ABOUT)
  1639. {
  1640. ret = ShellAbout(mb.hwndOwner, mb.lpszCaption, mb.lpszText, AppIcon);
  1641. }
  1642. else
  1643. {
  1644. if (flags & MB_USERICON)
  1645. {
  1646. //
  1647. // only use MessageBoxIndirect if we have to.
  1648. // has problems on win9x.
  1649. //
  1650. ret = MessageBoxIndirect(&mb);
  1651. }
  1652. else
  1653. {
  1654. //
  1655. // MessageBoxEx works great on both NT and Win95
  1656. //
  1657. ret = MessageBoxEx ( mb.hwndOwner, mb.lpszText, mb.lpszCaption,
  1658. mb.dwStyle, (WORD)mb.dwLanguageId );
  1659. }
  1660. }
  1661. //
  1662. // Free string memory; start processing tray msgs again
  1663. //
  1664. LocalFree( msgboxtext );
  1665. }
  1666. Waiting = FALSE;
  1667. return ret;
  1668. }
  1669. //
  1670. //********************************************************************
  1671. //
  1672. // WinMain
  1673. //
  1674. //********************************************************************
  1675. //
  1676. int NEAR PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
  1677. {
  1678. WNDCLASS cls;
  1679. MSG msg;
  1680. HWND hwnd;
  1681. INT iDisplay;
  1682. HINSTANCE hInstUser;
  1683. hInstApp = hInst;
  1684. szAppName = GetResourceString( IDS_TITLE );
  1685. //
  1686. // App is already running. Do not start a 2nd instance
  1687. //
  1688. if ( FindWindow( szAppName, szAppName ) )
  1689. {
  1690. return 0;
  1691. }
  1692. if (hInstUser=GetModuleHandle(TEXT("user32.dll")))
  1693. {
  1694. lpfnEDD = GetProcAddress( hInstUser, ENUMDISPLAYDEVICES );
  1695. lpfnEDSEx = GetProcAddress( hInstUser, ENUMDISPLAYSETTINGSEX );
  1696. }
  1697. AppIcon = LoadIcon(hInst,szAppName);
  1698. //
  1699. // Register a class for the main application window
  1700. //
  1701. cls.lpszClassName = szAppName;
  1702. cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  1703. cls.hInstance = hInstApp;
  1704. cls.hIcon = AppIcon;
  1705. cls.hCursor = LoadCursor(NULL,IDC_ARROW);
  1706. cls.lpszMenuName = szAppName;
  1707. cls.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
  1708. cls.lpfnWndProc = AppWndProc;
  1709. cls.cbWndExtra = 0;
  1710. cls.cbClsExtra = 0;
  1711. if (!RegisterClass(&cls))
  1712. return FALSE;
  1713. hwnd = CreateWindow(szAppName,
  1714. szAppName,
  1715. WS_OVERLAPPEDWINDOW,
  1716. CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
  1717. NULL, NULL,
  1718. hInstApp, NULL);
  1719. //
  1720. // Properties, about, exit - properties is the default
  1721. //
  1722. MainMenu = GetSubMenu(GetMenu(hwnd), 0);
  1723. SetMenuDefaultItem(MainMenu,MENU_PROPERTIES,MF_BYCOMMAND);
  1724. //
  1725. // Get flags from registry and build the modemenu
  1726. // from scratch.
  1727. //
  1728. GetQuickResFlags( );
  1729. if (!BuildMonitorArray())
  1730. {
  1731. return FALSE;
  1732. }
  1733. if (!BuildDevmodeLists())
  1734. {
  1735. return FALSE;
  1736. }
  1737. //
  1738. // Update tray tooltip to be current resolution
  1739. //
  1740. TrayMessage( hwnd, NIM_MODIFY, TRAY_ID, AppIcon );
  1741. //
  1742. // Polling messages from event queue
  1743. //
  1744. while (GetMessage(&msg, NULL, 0, 0))
  1745. {
  1746. TranslateMessage(&msg);
  1747. DispatchMessage(&msg);
  1748. }
  1749. //
  1750. // write flags to registry
  1751. //
  1752. SaveAllSettings();
  1753. //
  1754. // Free up dynamically allocated globals.
  1755. //
  1756. LocalFree ( szAppName );
  1757. for (iDisplay=0; iDisplay<iMonitors; iDisplay++)
  1758. {
  1759. if (pMonitors[iDisplay].DeviceName)
  1760. GlobalFree(pMonitors[iDisplay].DeviceName);
  1761. if (pMonitors[iDisplay].MonitorName)
  1762. GlobalFree(pMonitors[iDisplay].MonitorName);
  1763. if (pMonitors[iDisplay].PrimaryMonitorName)
  1764. GlobalFree(pMonitors[iDisplay].PrimaryMonitorName);
  1765. GlobalFree(pMonitors[iDisplay].pModes);
  1766. GlobalFree(pMonitors[iDisplay].FreqMenu);
  1767. }
  1768. GlobalFree(pMonitors);
  1769. return (int)msg.wParam;
  1770. }
  1771. //
  1772. //********************************************************************
  1773. //
  1774. // TrayMessage (HWND, DWORD, UINT, HICON )
  1775. //
  1776. // Add/remove icon to/from tray next to the time
  1777. //
  1778. //********************************************************************
  1779. //
  1780. BOOL TrayMessage(HWND hwnd, DWORD msg, UINT id, HICON hIcon )
  1781. {
  1782. NOTIFYICONDATA tnd;
  1783. PTCHAR Res=NULL;
  1784. PTCHAR Hz=NULL;
  1785. UINT uDisplay=0;
  1786. UINT uNewlen=0;
  1787. tnd.cbSize = sizeof(NOTIFYICONDATA);
  1788. tnd.hWnd = hwnd;
  1789. tnd.uID = id;
  1790. tnd.szTip[0] = '\0';
  1791. tnd.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;
  1792. tnd.uCallbackMessage = TRAY_MSG;
  1793. tnd.hIcon = hIcon;
  1794. //
  1795. // Changing tooltip text to match current resolution
  1796. // (Make sure pCurrentdm is valid / not NULL.)
  1797. //
  1798. if (msg == NIM_MODIFY)
  1799. {
  1800. do
  1801. {
  1802. if (pMonitors[uDisplay].pCurrentdm)
  1803. {
  1804. GetModeName(&(pMonitors[uDisplay].pCurrentdm->dm), &Res, &Hz);
  1805. //
  1806. // calculate how long the string will be (need to be sure it's < 64)
  1807. // old tip + new Res + Hz (if applicable) + ", " (if its not the 1st mon)
  1808. //
  1809. uNewlen = lstrlen(tnd.szTip);
  1810. if (Res)
  1811. {
  1812. uNewlen += lstrlen(Res);
  1813. }
  1814. if (uDisplay > 0)
  1815. {
  1816. uNewlen += 2;
  1817. }
  1818. if (fShowFreqs && Hz)
  1819. {
  1820. uNewlen += lstrlen(Hz);
  1821. }
  1822. if (uNewlen < 64)
  1823. {
  1824. //
  1825. // this displays information will fit in the tooltip
  1826. // add ", " if not 1st mon, then the Res, then Hz (if applicable)
  1827. //
  1828. if ( uDisplay > 0 )
  1829. {
  1830. lstrcat(tnd.szTip,TEXT(", "));
  1831. }
  1832. if (Res)
  1833. {
  1834. lstrcat(tnd.szTip,Res);
  1835. }
  1836. if (fShowFreqs && Hz)
  1837. {
  1838. lstrcat(tnd.szTip,Hz);
  1839. }
  1840. }
  1841. if (Res)
  1842. {
  1843. LocalFree(Res);
  1844. }
  1845. if (Hz)
  1846. {
  1847. LocalFree(Hz);
  1848. }
  1849. ++uDisplay;
  1850. }
  1851. } while (uDisplay < (UINT)iMonitors);
  1852. }
  1853. //
  1854. // Adding the tray icon - Current devmode
  1855. // is not known so use AppName as tip
  1856. //
  1857. else
  1858. {
  1859. wsprintf(tnd.szTip, szAppName);
  1860. }
  1861. return Shell_NotifyIcon( msg, &tnd );
  1862. }
  1863. //
  1864. //*****************************************************************************
  1865. //
  1866. // KeepNewResDlgProc(HWND, UINT, WPARAM, LPARAM )
  1867. //
  1868. // User must enter Yes to keep new res, or we default back to the old res.
  1869. //
  1870. //*****************************************************************************
  1871. //
  1872. INT_PTR FAR PASCAL KeepNewResDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  1873. {
  1874. //
  1875. // Save strings as static pointers, and free them only in YES/NO/ABORT/CANCEL,
  1876. // because they will otherwise disappear from a Win95 dialog box immediately
  1877. // after they are free'd.
  1878. //
  1879. static int NOTimeOut; // countdown to 0
  1880. static PTCHAR NewResString=NULL; // user friendly name for devmode
  1881. static PTCHAR NewHzString=NULL; // and frequency
  1882. static PTCHAR szAt=NULL; // ", at"
  1883. static PTCHAR TotalString=NULL; // "<wid x ht>, at <freq>"
  1884. switch (message)
  1885. {
  1886. case WM_INITDIALOG: // initialize values and focus
  1887. {
  1888. //
  1889. // Initialize values and focus
  1890. //
  1891. DEVMODE dm;
  1892. //
  1893. // Ignore tray messages while waiting for yes/no.
  1894. // Wait KEEP_RES_TIMEOUT seconds.
  1895. //
  1896. Waiting=TRUE;
  1897. //
  1898. // Get current devmode; lparam is the iDisplay
  1899. //
  1900. GetCurrentDevMode( (INT)lParam, &dm );
  1901. //
  1902. // Get user friendly strings (concatenate Res & Hz, if applicable)
  1903. //
  1904. GetModeName( &dm, &NewResString, &NewHzString);
  1905. if (NewResString)
  1906. {
  1907. if (fShowFreqs && NewHzString)
  1908. {
  1909. szAt = GetResourceString ( IDS_AT );
  1910. //
  1911. // Replace 2nd text item of msgbox
  1912. //
  1913. if (TotalString = LocalAlloc ( LPTR, sizeof(TCHAR)*
  1914. ( lstrlen(NewResString)+
  1915. lstrlen(NewHzString)+
  1916. lstrlen(szAt)+
  1917. 1 ) ))
  1918. {
  1919. lstrcpy(TotalString, NewResString);
  1920. lstrcat(TotalString, szAt);
  1921. lstrcat(TotalString, NewHzString);
  1922. SetDlgItemText(hDlg, IDTEXT2, TotalString);
  1923. }
  1924. }
  1925. else
  1926. {
  1927. SetDlgItemText(hDlg, IDTEXT2, NewResString);
  1928. }
  1929. }
  1930. //
  1931. // Set timeout length and start waiting
  1932. //
  1933. NOTimeOut=KEEP_RES_TIMEOUT;
  1934. SetTimer(hDlg,IDD_COUNTDOWN,1000,NULL);
  1935. return (TRUE);
  1936. break;
  1937. }
  1938. case WM_TIMER:
  1939. {
  1940. PTCHAR NoTextFmt=NULL; // "NO: %d"
  1941. PTCHAR NoText=NULL; // e.g. "NO: 15"
  1942. //
  1943. // Still counting down
  1944. //
  1945. if ( NOTimeOut >= 0 )
  1946. {
  1947. //
  1948. // Get format string for NO Button.
  1949. // Write it to NoText String and to dlg box
  1950. //
  1951. NoTextFmt = GetResourceString ( IDS_NOTEXT );
  1952. if (NoTextFmt)
  1953. {
  1954. NoText = LocalAlloc ( LPTR, sizeof(TCHAR)*
  1955. ( lstrlen(NoTextFmt)+1 ) );
  1956. wsprintf(NoText, NoTextFmt, NOTimeOut--);
  1957. SetDlgItemText(hDlg, IDNO, NoText);
  1958. LocalFree ( NoTextFmt );
  1959. LocalFree ( NoText );
  1960. }
  1961. }
  1962. else
  1963. {
  1964. //
  1965. // Give up on the user - return NO
  1966. //
  1967. KillTimer(hDlg, IDD_COUNTDOWN);
  1968. SendMessage(hDlg, WM_COMMAND, IDNO, 0);
  1969. }
  1970. return (TRUE);
  1971. }
  1972. break;
  1973. case WM_COMMAND:
  1974. //
  1975. // Start processing tray messages again
  1976. //
  1977. Waiting=FALSE;
  1978. switch (LOWORD(wParam))
  1979. {
  1980. //
  1981. // return value based on the button pressed
  1982. //
  1983. case IDYES :
  1984. case IDNO :
  1985. case IDABORT :
  1986. case IDCANCEL :
  1987. //
  1988. // LocalFree handles NULL pointers gracefully (does nothing)
  1989. //
  1990. LocalFree ( szAt );
  1991. LocalFree ( NewResString );
  1992. LocalFree ( NewHzString );
  1993. LocalFree ( TotalString );
  1994. EndDialog(hDlg, LOWORD(wParam));
  1995. return (TRUE);
  1996. break;
  1997. default:
  1998. break;
  1999. } // switch (wParam)
  2000. break;
  2001. default:
  2002. break;
  2003. } // switch (message)
  2004. return (FALSE); // Didn't process a message
  2005. } // KeepNewResDlgProc()
  2006. //
  2007. //*****************************************************************************
  2008. //
  2009. // NTOptionsDlgProc(HWND, UINT, WPARAM, LPARAM )
  2010. //
  2011. //
  2012. //
  2013. //*****************************************************************************
  2014. //
  2015. INT_PTR FAR PASCAL NTOptionsDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  2016. {
  2017. INT i;
  2018. static WORD SaveQRFlags;
  2019. switch (message)
  2020. {
  2021. case WM_INITDIALOG:
  2022. //
  2023. // Stop processing tray messages; check buttons properly
  2024. //
  2025. Waiting = TRUE;
  2026. SaveQRFlags = QuickResFlags;
  2027. CheckRadioButton(hDlg,IDD_SORT_RES,IDD_SORT_BPP,
  2028. (fSortByBPP ? IDD_SORT_BPP : IDD_SORT_RES) );
  2029. CheckRadioButton(hDlg,IDD_SUBMENUS,IDD_ALLMODEMENU, FreqMenuLocation );
  2030. CheckDlgButton(hDlg, IDD_UPDATEREG, fUpdateReg );
  2031. CheckDlgButton(hDlg, IDD_REMMODES, fRememberModes );
  2032. CheckDlgButton(hDlg, IDD_RESTARTREQ, fShowModesThatNeedRestart );
  2033. CheckDlgButton(hDlg, IDD_SHOWTESTED, fShowTestedModes );
  2034. return TRUE;
  2035. break;
  2036. case WM_COMMAND:
  2037. switch (LOWORD(wParam))
  2038. {
  2039. //
  2040. // Update buttons : sorting by BPP or Res?
  2041. //
  2042. case IDD_SORT_RES:
  2043. case IDD_SORT_BPP:
  2044. CheckRadioButton(hDlg,IDD_SORT_RES,IDD_SORT_BPP,LOWORD(wParam));
  2045. return TRUE;
  2046. break;
  2047. //
  2048. // Update buttons : where to display freq menus?
  2049. //
  2050. case IDD_SUBMENUS:
  2051. case IDD_ONEMENUMOBILE:
  2052. case IDD_ONEMENUBOTTOM:
  2053. case IDD_ALLMODEMENU:
  2054. CheckRadioButton(hDlg,IDD_SUBMENUS,IDD_ALLMODEMENU,LOWORD(wParam));
  2055. return TRUE;
  2056. break;
  2057. //
  2058. // Clear all registry remembered settings
  2059. // Make user verify he did this on purpose
  2060. //
  2061. case IDD_CLEARREG:
  2062. if (MsgBox(IDS_CLEARREG,
  2063. 0,
  2064. MB_YESNO | MB_ICONQUESTION | MB_TASKMODAL)
  2065. == IDYES)
  2066. {
  2067. //
  2068. // Reset flags for all monitors; destroy and rebuild
  2069. // each mode menu
  2070. //
  2071. for (i=0; i<iMonitors; i++)
  2072. {
  2073. SetDevmodeFlags(i, TRUE);
  2074. VALIDMODE(pMonitors[i].pCurrentdm) = MODE_BESTHZ;
  2075. DestroyModeMenu( i, TRUE, FALSE);
  2076. }
  2077. }
  2078. return TRUE;
  2079. break;
  2080. //
  2081. // XOR QuickResFlags on and off
  2082. //
  2083. case IDD_UPDATEREG:
  2084. QuickResFlags ^= QF_UPDATEREG;
  2085. return TRUE;
  2086. break;
  2087. case IDD_REMMODES:
  2088. QuickResFlags ^= QF_REMMODES;
  2089. return TRUE;
  2090. break;
  2091. case IDD_RESTARTREQ:
  2092. QuickResFlags ^= QF_SHOWRESTART;
  2093. return TRUE;
  2094. break;
  2095. case IDD_SHOWTESTED:
  2096. QuickResFlags ^= QF_SHOWTESTED;
  2097. return TRUE;
  2098. break;
  2099. case IDOK:
  2100. {
  2101. BOOL bRebuildMenu = FALSE;
  2102. BOOL bNeedToSort = FALSE;
  2103. //
  2104. // See if sort order has changed.
  2105. //
  2106. if ( (IsDlgButtonChecked (hDlg, IDD_SORT_RES) && fSortByBPP) ||
  2107. (IsDlgButtonChecked (hDlg, IDD_SORT_BPP) && !fSortByBPP) )
  2108. {
  2109. QuickResFlags ^= QF_SORT_BYBPP;
  2110. bNeedToSort = TRUE;
  2111. }
  2112. //
  2113. // If "show modes that require restart", or "show tested "modes only",
  2114. // then rebuild menu is required
  2115. //
  2116. if ( (fShowModesThatNeedRestart != (SaveQRFlags & QF_SHOWRESTART)) ||
  2117. (fShowTestedModes != (SaveQRFlags & QF_SHOWTESTED))
  2118. )
  2119. {
  2120. bRebuildMenu = TRUE;
  2121. }
  2122. //
  2123. // see if FreqMenuLocation has changed
  2124. //
  2125. if (!IsDlgButtonChecked (hDlg, FreqMenuLocation))
  2126. {
  2127. WORD i;
  2128. //
  2129. // Freq menu location has changed; update & ask for rebuild
  2130. //
  2131. bRebuildMenu = TRUE;
  2132. for ( i=IDD_SUBMENUS; i <= IDD_ALLMODEMENU; i++ )
  2133. {
  2134. if (IsDlgButtonChecked (hDlg, i))
  2135. {
  2136. FreqMenuLocation = i;
  2137. }
  2138. }
  2139. }
  2140. //
  2141. // If rebuilding and or resorting, just destroy & rebuild the menus
  2142. //
  2143. if ( bNeedToSort || bRebuildMenu )
  2144. {
  2145. for (i=0; i<iMonitors; i++)
  2146. DestroyModeMenu( i, TRUE, bNeedToSort);
  2147. }
  2148. SaveAllSettings();
  2149. Waiting = FALSE;
  2150. EndDialog(hDlg, LOWORD(wParam));
  2151. return TRUE;
  2152. break;
  2153. }
  2154. case IDCANCEL :
  2155. Waiting = FALSE;
  2156. QuickResFlags = SaveQRFlags;
  2157. EndDialog(hDlg, LOWORD(wParam));
  2158. return TRUE;
  2159. break;
  2160. default:
  2161. break;
  2162. } // switch (wParam)
  2163. break;
  2164. default:
  2165. break;
  2166. } // switch (message)
  2167. return FALSE; // Didn't process a message
  2168. } // NTOptionsDlgProc()
  2169. //
  2170. //*****************************************************************************
  2171. //
  2172. // W95OptionsDlgProc(HWND, UINT, WPARAM, LPARAM )
  2173. //
  2174. //
  2175. //
  2176. //*****************************************************************************
  2177. //
  2178. INT_PTR FAR PASCAL W95OptionsDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  2179. {
  2180. INT i;
  2181. static WORD SaveQRFlags;
  2182. switch (message)
  2183. {
  2184. case WM_INITDIALOG:
  2185. //
  2186. // Stop processing tray messages; check buttons properly
  2187. //
  2188. Waiting = TRUE;
  2189. SaveQRFlags = QuickResFlags;
  2190. CheckRadioButton(hDlg,IDD_SORT_RES,IDD_SORT_BPP,
  2191. (fSortByBPP ? IDD_SORT_BPP : IDD_SORT_RES) );
  2192. CheckDlgButton(hDlg, IDD_UPDATEREG, fUpdateReg );
  2193. CheckDlgButton(hDlg, IDD_REMMODES, fRememberModes );
  2194. CheckDlgButton(hDlg, IDD_RESTARTREQ, fShowModesThatNeedRestart );
  2195. CheckDlgButton(hDlg, IDD_SHOWTESTED, fShowTestedModes );
  2196. return TRUE;
  2197. break;
  2198. case WM_COMMAND:
  2199. switch (LOWORD(wParam))
  2200. {
  2201. //
  2202. // Update buttons : sorting by BPP or Res?
  2203. //
  2204. case IDD_SORT_RES:
  2205. case IDD_SORT_BPP:
  2206. CheckRadioButton(hDlg,IDD_SORT_RES,IDD_SORT_BPP,LOWORD(wParam));
  2207. return TRUE;
  2208. break;
  2209. //
  2210. // Clear all registry remembered settings
  2211. // Make user verify he did this on purpose
  2212. //
  2213. case IDD_CLEARREG:
  2214. if (MsgBox(IDS_CLEARREG,
  2215. 0,
  2216. MB_YESNO | MB_ICONQUESTION | MB_TASKMODAL)
  2217. == IDYES)
  2218. {
  2219. //
  2220. // Reset flags for all monitors; destroy and rebuild
  2221. // each mode menu
  2222. //
  2223. for (i=0; i<iMonitors; i++)
  2224. {
  2225. SetDevmodeFlags(i, TRUE);
  2226. VALIDMODE(pMonitors[i].pCurrentdm) = MODE_BESTHZ;
  2227. DestroyModeMenu( i, TRUE, FALSE);
  2228. }
  2229. }
  2230. return TRUE;
  2231. break;
  2232. //
  2233. // XOR QuickResFlags on and off
  2234. //
  2235. case IDD_UPDATEREG:
  2236. QuickResFlags ^= QF_UPDATEREG;
  2237. return TRUE;
  2238. break;
  2239. case IDD_REMMODES:
  2240. QuickResFlags ^= QF_REMMODES;
  2241. return TRUE;
  2242. break;
  2243. case IDD_RESTARTREQ:
  2244. QuickResFlags ^= QF_SHOWRESTART;
  2245. return TRUE;
  2246. break;
  2247. case IDD_SHOWTESTED:
  2248. QuickResFlags ^= QF_SHOWTESTED;
  2249. return TRUE;
  2250. break;
  2251. case IDOK:
  2252. {
  2253. BOOL bNeedToSort = FALSE;
  2254. //
  2255. // Note if the sort order has changed
  2256. //
  2257. if ( (IsDlgButtonChecked (hDlg, IDD_SORT_RES) && fSortByBPP) ||
  2258. (IsDlgButtonChecked (hDlg, IDD_SORT_BPP) && !fSortByBPP) )
  2259. {
  2260. QuickResFlags ^= QF_SORT_BYBPP;
  2261. bNeedToSort = TRUE;
  2262. }
  2263. //
  2264. // If "sort order", "show modes that require restart", or "show tested
  2265. // "modes only" changed, then destroy and rebuild old menu (resort if nec.)
  2266. //
  2267. if ( bNeedToSort ||
  2268. (fShowModesThatNeedRestart != (SaveQRFlags & QF_SHOWRESTART)) ||
  2269. (fShowTestedModes != (SaveQRFlags & QF_SHOWTESTED))
  2270. )
  2271. {
  2272. for (i=0; i<iMonitors; i++)
  2273. DestroyModeMenu( i, TRUE, bNeedToSort);
  2274. }
  2275. SaveAllSettings();
  2276. //
  2277. // No break after IDOK, by design.
  2278. // IDOK AND IDCANCEL : start processing tray clicks,
  2279. // and return ok/cancel as return value.
  2280. //
  2281. }
  2282. case IDCANCEL :
  2283. Waiting = FALSE;
  2284. EndDialog(hDlg, LOWORD(wParam));
  2285. return TRUE;
  2286. break;
  2287. default:
  2288. break;
  2289. } // switch (wParam)
  2290. break;
  2291. default:
  2292. break;
  2293. } // switch (message)
  2294. return FALSE; // Didn't process a message
  2295. } // W95OptionsDlgProc()