mirror of https://github.com/lianthony/NT4.0
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.
2295 lines
53 KiB
2295 lines
53 KiB
//***************************************************************************
|
|
//
|
|
// QuickRes for Windows NT
|
|
//
|
|
// Tray app to change your display resolution quickly.
|
|
//
|
|
// written by ToddLa
|
|
//
|
|
// NOTE there is a good reason this is a 16bit app...???
|
|
//
|
|
// 03/03/96 - ChrisW : Get to build on NT
|
|
// 03/06/96 - MDesai : Finish porting; add submenus with frequencies;
|
|
// Test for valid devmode.
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
// Known bugs - These bugs are when running on win95 ONLY.
|
|
// 1. First time the menu is displayed, the current mode
|
|
// is not highlighted and checked.
|
|
// 2. KeepNewRes dlg box does NOT properly display the string
|
|
// for the new resolution being tested.
|
|
//
|
|
//***************************************************************************
|
|
|
|
|
|
#include "QuickRes.h"
|
|
|
|
|
|
PTCHAR szAppName;
|
|
|
|
HINSTANCE hInstApp;
|
|
HICON AppIcon;
|
|
|
|
|
|
//
|
|
// devmode menu and freq submenus built on the fly
|
|
//
|
|
|
|
HMENU ModeMenu=NULL;
|
|
HMENU FreqMenu[MAX_RESANDBPP_SETTINGS];
|
|
|
|
|
|
//
|
|
// options, properties, about and exit...
|
|
//
|
|
|
|
HMENU MainMenu;
|
|
|
|
|
|
//
|
|
// number of devmodes in pModes
|
|
//
|
|
|
|
INT iModes=0;
|
|
|
|
|
|
//
|
|
// array of devmodes display can handle, and
|
|
// pointer in pModes to current devmode
|
|
//
|
|
|
|
PDEVMODE pModes=NULL;
|
|
PDEVMODE pCurrentdm=NULL;
|
|
|
|
|
|
//
|
|
// Waiting for a Popup - don't process any tray messages
|
|
//
|
|
|
|
BOOL Waiting=FALSE;
|
|
|
|
|
|
//
|
|
// Flags: update registry, show restart modes, sort order
|
|
// also where the freq menu(s) go.
|
|
//
|
|
WORD QuickResFlags;
|
|
WORD FreqMenuLocation;
|
|
|
|
|
|
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
// GetResourceString( UINT )
|
|
//
|
|
// Load a resource string into a LPTSTR - the memory for the string
|
|
// is dynamically allocated. The callee must free the memory!
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
|
|
LPTSTR GetResourceString ( UINT ResourceID )
|
|
{
|
|
|
|
|
|
INT BuffSize=RESOURCE_STRINGLEN; // current max size of string
|
|
PTCHAR BigBuf; // buffer to find size of resource
|
|
PTCHAR ResBuf; // buffer for resource
|
|
INT len; // length of the resource
|
|
|
|
|
|
while (1)
|
|
{
|
|
|
|
//
|
|
// Allocate hopefully oversized buffer
|
|
//
|
|
|
|
if( !(BigBuf= LocalAlloc( LPTR, BuffSize ) ) )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Try to read string into BigBuf to get its length
|
|
//
|
|
|
|
if ( !(len = LoadString(hInstApp, ResourceID, BigBuf, BuffSize)) )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Buffer is too small - try again.
|
|
//
|
|
|
|
if( len >= BuffSize-1 )
|
|
{
|
|
BuffSize <<= 1;
|
|
LocalFree ( BigBuf );
|
|
}
|
|
|
|
else
|
|
{
|
|
|
|
//
|
|
// Reallocate properly sized string buffer,
|
|
// and copy string into it
|
|
//
|
|
|
|
len = ( len + 1 ) * sizeof( TCHAR );
|
|
|
|
if (ResBuf = LocalAlloc( LPTR, len ))
|
|
{
|
|
lstrcpyn ( ResBuf, BigBuf, len );
|
|
}
|
|
|
|
LocalFree ( BigBuf );
|
|
|
|
return( ResBuf );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
// GetModeName( PDEVMODE, PTCHAR*, PTCHAR* )
|
|
//
|
|
// Translate devmode into user friendly strings-
|
|
// one for resolution and color depth; one for refresh rate
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
|
|
void GetModeName(PDEVMODE pDevMode, PTCHAR *szMode, PTCHAR *szFreq )
|
|
{
|
|
|
|
PTCHAR FmtRes; // Format strings for
|
|
PTCHAR FmtHz; // resolution and Hz
|
|
|
|
|
|
//
|
|
// Load format string corresponding to devmode
|
|
//
|
|
|
|
FmtRes = GetResourceString ( IDS_CRES + BPP(pDevMode) );
|
|
|
|
|
|
//
|
|
// Use Default Freq string if necessary
|
|
//
|
|
|
|
if( HZ(pDevMode) == 0 || HZ(pDevMode) == 1)
|
|
{
|
|
FmtHz = GetResourceString ( IDS_DEFHERTZ );
|
|
}
|
|
else
|
|
{
|
|
FmtHz = GetResourceString ( IDS_HERTZ );
|
|
}
|
|
|
|
|
|
//
|
|
// return separate resolution and frequency strings
|
|
// need to convert "%d"-> "12345", add byte for '\0'
|
|
//
|
|
|
|
if (FmtRes)
|
|
{
|
|
if (*szMode = LocalAlloc( LPTR, sizeof(TCHAR)*
|
|
(lstrlen(FmtRes)+2*INT_FORMAT_TO_5_DIGITS+1 ) ))
|
|
{
|
|
wsprintf(*szMode, FmtRes, XRES(pDevMode), YRES(pDevMode) );
|
|
}
|
|
|
|
LocalFree ( FmtRes );
|
|
}
|
|
|
|
|
|
if (FmtHz)
|
|
{
|
|
|
|
if (*szFreq = LocalAlloc ( LPTR, sizeof(TCHAR)*
|
|
(lstrlen(FmtHz)+INT_FORMAT_TO_5_DIGITS+1) ))
|
|
{
|
|
wsprintf(*szFreq, FmtHz, HZ(pDevMode));
|
|
}
|
|
|
|
LocalFree ( FmtHz );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
// GetCurrentDevMode( PDEVMODE )
|
|
//
|
|
// Get a pointer to the current devmode into *pDM
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
|
|
PDEVMODE GetCurrentDevMode(PDEVMODE pDM)
|
|
{
|
|
|
|
pDM->dmSize= sizeof(DEVMODE);
|
|
|
|
//
|
|
// NT specific; returns current devmode
|
|
//
|
|
|
|
EnumDisplaySettings( NULL, (DWORD)ENUM_CURRENT_SETTINGS, pDM );
|
|
|
|
return pDM;
|
|
}
|
|
|
|
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
// SetMode( HWND UINT )
|
|
//
|
|
// Set the new devmode and update registry on request using
|
|
// the CDS_UPDATEREGISTRY flag. If user wants to change and
|
|
// restart, then we need to update the registry and restart.
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
|
|
BOOL SetMode( HWND hwnd, UINT index )
|
|
{
|
|
DWORD CDSret; // ret value, ChangeDisplaySettings
|
|
DWORD CDSFlags=CDS_FULLSCREEN; // 2nd param of call to CDS
|
|
UINT DialogBoxRet=0; // IDYES/NO/ABORT/CANCEL
|
|
PDEVMODE pSave = pCurrentdm; // save current mode ptr
|
|
PDEVMODE pdm = &pModes[index]; // new mode to be set
|
|
BOOL bChange=FALSE; // changing modes or not
|
|
|
|
|
|
//
|
|
// If user wants to update registry
|
|
//
|
|
|
|
if( fUpdateReg )
|
|
{
|
|
CDSFlags |= CDS_UPDATEREGISTRY;
|
|
}
|
|
|
|
|
|
//
|
|
// Tell CDS what fields may be changing
|
|
// Also, keep appwndproc from doing anything while we are testing
|
|
//
|
|
|
|
pdm->dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
|
|
Waiting=TRUE;
|
|
|
|
//
|
|
// Call CDS and update registry on request. (If it is
|
|
// a known bad mode give user chance to change his mind.)
|
|
//
|
|
|
|
if( (VALIDMODE(&pModes[index]) != MODE_INVALID ) ||
|
|
( MsgBox( IDS_INVALIDMODE, 0, MB_YESNO | MB_ICONEXCLAMATION )==IDYES ) )
|
|
{
|
|
|
|
CDSret = ChangeDisplaySettings( pdm, CDSFlags);
|
|
|
|
if (CDSret == DISP_CHANGE_SUCCESSFUL)
|
|
{
|
|
|
|
//
|
|
// Even though it may be temporary, current dm has changed.
|
|
// Need to reset pCurrentdm to point to new current DM.
|
|
// Change tooltip to reflect old settings
|
|
//
|
|
|
|
pCurrentdm = pdm;
|
|
|
|
TrayMessage(hwnd, NIM_MODIFY, TRAY_ID, AppIcon);
|
|
|
|
|
|
//
|
|
// Return value claims that it 'worked.' But, it may not visible
|
|
// to the user (e.g. the mode is unsupported by the monitor).
|
|
// If the User has not already approved this new resolution,
|
|
// then make the user approve the change, or we default back to
|
|
// the last devmode.
|
|
//
|
|
|
|
if ( fGoodMode(&pModes[index]) )
|
|
{
|
|
//
|
|
// VALID or BESTHZ modes - go ahead and change
|
|
//
|
|
|
|
bChange = TRUE;
|
|
}
|
|
|
|
else
|
|
{
|
|
//
|
|
// Ask user if it looks okay
|
|
// Flag the mode based on return value.
|
|
//
|
|
|
|
switch( DialogBoxRet = DialogBox(hInstApp,
|
|
MAKEINTRESOURCE(KeepNewRes),
|
|
NULL,
|
|
KeepNewResDlgProc) )
|
|
{
|
|
|
|
//
|
|
// There should NOT be a break after
|
|
// IDYES. Fall thru by design.
|
|
//
|
|
case IDYES: bChange = TRUE;
|
|
|
|
case IDABORT: VALIDMODE(&pModes[index]) = MODE_VALID;
|
|
break;
|
|
|
|
case IDNO:
|
|
case IDCANCEL: VALIDMODE(&pModes[index]) = MODE_INVALID;
|
|
break;
|
|
|
|
} // switch
|
|
|
|
} // else - MODE_INVALID
|
|
|
|
}
|
|
|
|
else // CDSret != DISP_CHANGE_SUCCESSFUL
|
|
{
|
|
//
|
|
// Requires restart. Ask user if thats okay.
|
|
//
|
|
|
|
if (CDSret == DISP_CHANGE_RESTART)
|
|
{
|
|
|
|
if ( MsgBox(IDS_RESTART, 0, MB_YESNO) == IDYES )
|
|
{
|
|
|
|
//
|
|
// After restart all modes will need to be tested again?
|
|
//
|
|
|
|
SetDevmodeFlags ( TRUE );
|
|
|
|
|
|
//
|
|
// Need to call CDS again if registry was not updated
|
|
//
|
|
|
|
if ( !(CDSFlags & CDS_UPDATEREGISTRY) )
|
|
{
|
|
ChangeDisplaySettings( pdm, (CDSFlags | CDS_UPDATEREGISTRY) );
|
|
}
|
|
|
|
ExitWindows(EW_RESTARTWINDOWS, 0);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// Tell user we cannot change to this devmode
|
|
//
|
|
|
|
MsgBox(IDS_CANTSETMODE, 0, MB_OK);
|
|
}
|
|
|
|
} // end else != DISP_CHANGE_SUCCESSFUL
|
|
|
|
|
|
if (bChange)
|
|
{
|
|
//
|
|
// Changing to a valid mode; destroy and rebuild menu
|
|
//
|
|
|
|
if ((FreqMenuLocation == IDD_ONEMENUMOBILE) ||
|
|
(FreqMenuLocation == IDD_ONEMENUBOTTOM) )
|
|
{
|
|
VALIDMODE(pCurrentdm) = MODE_BESTHZ;
|
|
}
|
|
|
|
DestroyModeMenu(TRUE,FALSE);
|
|
}
|
|
|
|
else // !bChange
|
|
{
|
|
//
|
|
// Change back to last good devmode;
|
|
// do not have to recheck menuitems
|
|
//
|
|
|
|
//
|
|
// Need to change menuitem in the mode menu if it failed
|
|
//
|
|
|
|
pCurrentdm = pSave;
|
|
|
|
|
|
//
|
|
// Change back, and reset registry if we had set it above
|
|
// Change tooltip to reflect old settings
|
|
//
|
|
|
|
ChangeDisplaySettings( pCurrentdm, CDSFlags );
|
|
|
|
TrayMessage(hwnd, NIM_MODIFY, TRAY_ID, AppIcon);
|
|
|
|
} // bChange
|
|
|
|
|
|
} // endif
|
|
|
|
|
|
//
|
|
// Show modemenu again; allow appwndproc to process messages
|
|
//
|
|
|
|
if (!bChange)
|
|
{
|
|
SetTimer(hwnd, TRAY_ID, 10, NULL);
|
|
}
|
|
|
|
Waiting=FALSE;
|
|
|
|
|
|
//
|
|
// if Current hasnt changed then we return false
|
|
//
|
|
|
|
return (bChange);
|
|
|
|
}
|
|
|
|
|
|
//
|
|
//********************************************************************
|
|
//
|
|
// CompareDevmodes ( PDEVMODE, PDEVMODE )
|
|
//
|
|
// Compares 2 devmodes -
|
|
// Returns 0 if equal, -1 if first > second, +1 if first < second
|
|
//
|
|
// msb to lsb: xres, yres, bpp, hertz
|
|
//********************************************************************
|
|
//
|
|
|
|
int _cdecl CompareDevmodes( PDEVMODE pDm1, PDEVMODE pDm2 )
|
|
{
|
|
INT compare;
|
|
|
|
|
|
//
|
|
// Compare Xs, then Ys, BPP, and Hz.
|
|
//
|
|
|
|
if ( !fSortByBPP || ((compare= BPP(pDm1) - BPP(pDm2)) == 0))
|
|
{
|
|
if( (compare= ( XRES(pDm1) - XRES(pDm2) ) ) == 0 )
|
|
{
|
|
if( (compare= ( YRES(pDm1) - YRES(pDm2) ) ) == 0 )
|
|
{
|
|
if ( fSortByBPP || ((compare= BPP(pDm1) - BPP(pDm2)) == 0))
|
|
{
|
|
compare= HZ(pDm1) - HZ(pDm2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set return value as -1, 0, or 1 only
|
|
//
|
|
|
|
if( compare < 0)
|
|
{
|
|
compare= -1;
|
|
}
|
|
|
|
else
|
|
{
|
|
if( compare > 0 )
|
|
{
|
|
compare= 1;
|
|
}
|
|
}
|
|
|
|
return( compare );
|
|
|
|
}
|
|
|
|
|
|
//
|
|
//********************************************************************
|
|
//
|
|
// CheckMenuItemCurrentMode ( )
|
|
//
|
|
// Traverse all menu items and check the Hz value corresponding
|
|
// to the current mode. Also, highlight the current resolution/
|
|
// BPP as defaultmenuitem
|
|
//
|
|
//********************************************************************
|
|
//
|
|
|
|
void CheckMenuItemCurrentMode( )
|
|
{
|
|
|
|
int i; // counter
|
|
DEVMODE dm; // temporary storage for current DM
|
|
HMENU hMenu; // Frequency submenu for a given Res/BPP
|
|
SHORT MenuItem; // Menu item for exact devmode
|
|
DWORD dwSta; // returns status variable
|
|
|
|
|
|
//
|
|
// Need a pointer to the current devmode. This function will search
|
|
// pModes trying to match the devmode pointed to by pCurrentdm.
|
|
// After the 1st time through, pCurrentdm will be a ptr IN pModes
|
|
//
|
|
|
|
if (!pCurrentdm)
|
|
{
|
|
//
|
|
// Get current devmode
|
|
//
|
|
|
|
pCurrentdm = GetCurrentDevMode(&dm);
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Uncheck all menu items
|
|
//
|
|
|
|
for( i=0; i<iModes; i++ )
|
|
{
|
|
|
|
hMenu = FreqMenu[FREQMENU( &pModes[i] )];
|
|
MenuItem= MENUITEM( &pModes[i] );
|
|
|
|
//
|
|
// Uncheck thew Hz in the FreqMenu (if appliacable); uncheck item on mode menu
|
|
//
|
|
|
|
if (hMenu)
|
|
{
|
|
dwSta= CheckMenuItem(hMenu, MenuItem, MF_BYCOMMAND|MF_UNCHECKED);
|
|
CheckMenuItem(ModeMenu, FREQMENU( &pModes[i] ), MF_BYPOSITION | MF_UNCHECKED );
|
|
}
|
|
|
|
CheckMenuItem(ModeMenu, MenuItem, MF_BYCOMMAND | MF_UNCHECKED );
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Check the current one
|
|
//
|
|
|
|
for( i=0; i<iModes; i++ )
|
|
{
|
|
|
|
//
|
|
// Go through the array looking for a match of the current devmode
|
|
//
|
|
|
|
if( ( CompareDevmodes( pCurrentdm, &pModes[i] ) ) == 0 )
|
|
{
|
|
|
|
//
|
|
// Found it!
|
|
// Get the menu item ID for this devmode and which
|
|
// frequency submenu it is a part of.
|
|
//
|
|
|
|
hMenu = FreqMenu[FREQMENU( &pModes[i] )];
|
|
MenuItem= MENUITEM( &pModes[i] );
|
|
|
|
|
|
//
|
|
// Save this ptr in the pCurrentdm variable
|
|
// check menu item on mode menu and check mode
|
|
// on frequency submenu (if applicable)
|
|
//
|
|
|
|
pCurrentdm = &pModes[i];
|
|
|
|
if (hMenu)
|
|
{
|
|
dwSta= CheckMenuItem(hMenu, MenuItem, MF_BYCOMMAND|MF_CHECKED);
|
|
CheckMenuItem(ModeMenu, FREQMENU(&pModes[i]), MF_BYPOSITION | MF_CHECKED );
|
|
}
|
|
else
|
|
{
|
|
CheckMenuItem(ModeMenu, MenuItem, MF_BYCOMMAND | MF_CHECKED );
|
|
}
|
|
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
//********************************************************************
|
|
//
|
|
// DestroyModeMenu( BOOL bRebuild, BOOL bNeedtoSort )
|
|
//
|
|
// Free all frequency submenus and the mode menu
|
|
//
|
|
//********************************************************************
|
|
//
|
|
|
|
void DestroyModeMenu( BOOL bRebuild, BOOL bNeedtoSort)
|
|
{
|
|
|
|
UINT i;
|
|
|
|
|
|
//
|
|
// Free all frequency submenus
|
|
// There are a maximum of MAX_RESANDBPP_SETTINGS different
|
|
// frequency menus
|
|
//
|
|
|
|
for ( i = 0;
|
|
i < MAX_RESANDBPP_SETTINGS;
|
|
i++ )
|
|
{
|
|
|
|
if (IsMenu(FreqMenu[i]))
|
|
{
|
|
DestroyMenu( FreqMenu[i] );
|
|
FreqMenu[i] = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Free the mode menu (resolutions/BPP)
|
|
//
|
|
|
|
if (ModeMenu)
|
|
{
|
|
DestroyMenu(ModeMenu);
|
|
}
|
|
|
|
ModeMenu = NULL;
|
|
|
|
|
|
if (bRebuild)
|
|
{
|
|
GetModeMenu( bNeedtoSort );
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
//********************************************************************
|
|
//
|
|
// HandleFreqMenu( )
|
|
//
|
|
// Either append submenu to res/bpp, save it for later, or
|
|
// ditch it and put all Hz entries on mode menu.
|
|
// If there is only one Hz for a given Res, we dont need it.
|
|
//
|
|
//********************************************************************
|
|
//
|
|
VOID HandleFreqMenu( short FreqCount, short ResCounter, int pFirst)
|
|
{
|
|
|
|
PTCHAR Res=NULL;
|
|
PTCHAR Hz=NULL;
|
|
|
|
|
|
GetModeName(&pModes[pFirst], &Res, &Hz);
|
|
|
|
//
|
|
// Dont use submenus if there is only 1 Hz
|
|
// Concatenate Res & Hz into one string.
|
|
// This is always true when freqmwnulocation==IDD_ALLMODEMENU
|
|
//
|
|
|
|
if ( FreqCount == 1 )
|
|
{
|
|
PTCHAR ResHz;
|
|
|
|
if (ResHz=LocalAlloc( LPTR, sizeof(TCHAR)*
|
|
(lstrlen(Res)+lstrlen(Hz)+1) ))
|
|
{
|
|
wsprintf(ResHz,TEXT("%s%s"),Res,Hz);
|
|
AppendMenu(ModeMenu, MF_STRING, MENU_RES+pFirst, ResHz);
|
|
}
|
|
|
|
FreqMenu[ResCounter] == NULL;
|
|
LocalFree(ResHz);
|
|
}
|
|
|
|
else
|
|
{
|
|
SHORT i=0;
|
|
SHORT nAppended=0;
|
|
|
|
|
|
//
|
|
// Create Popup and append all Hz strings
|
|
// Append FreqCount items, possibly skipping over some modes
|
|
//
|
|
|
|
FreqMenu[ResCounter] = CreatePopupMenu();
|
|
|
|
for (i=0; nAppended < FreqCount; i++)
|
|
{
|
|
|
|
PTCHAR LoopRes=NULL;
|
|
PTCHAR LoopHz=NULL;
|
|
|
|
//
|
|
// Skip untested modes if requested. FreqCount does NOT
|
|
// include skipped modes, so we count up with nAppended, not i.
|
|
//
|
|
|
|
if ( !fShowTestedModes || fGoodMode(&pModes[pFirst+i]) )
|
|
{
|
|
|
|
GetModeName(&pModes[pFirst+i],&LoopRes,&LoopHz);
|
|
AppendMenu(FreqMenu[ResCounter],MF_STRING,MENU_RES+pFirst+i,LoopHz);
|
|
nAppended++;
|
|
|
|
LocalFree(LoopRes);
|
|
LocalFree(LoopHz);
|
|
LoopRes=NULL;
|
|
LoopHz=NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Hang menu off side of each bpp/res
|
|
//
|
|
|
|
if (FreqMenuLocation == IDD_SUBMENUS)
|
|
{
|
|
AppendMenu(ModeMenu,MF_POPUP,(UINT)FreqMenu[ResCounter],Res);
|
|
}
|
|
|
|
else
|
|
{
|
|
//
|
|
// Only show submenu for the current mode
|
|
// Use BESTHZ mode or the VALID mode with the
|
|
// lowest frequency.
|
|
//
|
|
|
|
if ( (FreqMenuLocation == IDD_ONEMENUMOBILE) ||
|
|
(FreqMenuLocation == IDD_ONEMENUBOTTOM) )
|
|
{
|
|
|
|
SHORT BestHz=0;
|
|
SHORT index;
|
|
|
|
//
|
|
// Start with highest freq (pFirst+i-1)
|
|
// and work down to pFirst looking for BestHz.
|
|
// if we find BESTHZ use that one, else
|
|
// use last VALIDMODE we get before loop ends
|
|
//
|
|
|
|
for (index=pFirst+i-1 ; index >= pFirst; index--)
|
|
{
|
|
if ( VALIDMODE(&pModes[index]) == MODE_BESTHZ )
|
|
{
|
|
BestHz = index;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (VALIDMODE(&pModes[index])!=MODE_INVALID)
|
|
{
|
|
BestHz = index;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// No valid/besthz modes. Use smallest Hz for that Res
|
|
//
|
|
|
|
if (!BestHz)
|
|
{
|
|
BestHz = pFirst;
|
|
}
|
|
|
|
AppendMenu(ModeMenu,MF_STRING,MENU_RES+BestHz,Res);
|
|
}
|
|
}
|
|
}
|
|
|
|
LocalFree(Res);
|
|
LocalFree(Hz);
|
|
|
|
}
|
|
|
|
|
|
//
|
|
//********************************************************************
|
|
//
|
|
// GetModeMenu( BOOL )
|
|
//
|
|
// Build the mode menu with each resolution/BPP having a
|
|
// pointer to its own frequency submenu
|
|
//
|
|
//********************************************************************
|
|
//
|
|
|
|
HMENU GetModeMenu ( BOOL bNeedtoSort )
|
|
{
|
|
|
|
int n; // counter
|
|
BOOL bMajorChange=FALSE; // change in the major sort order field
|
|
BOOL bMinorChange=FALSE; // change in the minor sort order field
|
|
SHORT FreqCount=0; // number of freqs on the current submenu
|
|
SHORT ResCounter=0; // Res/Color defines the freqmenu #
|
|
INT FirstMode=-1; // index in pmodes; 1st mode for given res/bpp
|
|
|
|
|
|
if (!ModeMenu)
|
|
{
|
|
ModeMenu = CreatePopupMenu();
|
|
|
|
|
|
if (bNeedtoSort)
|
|
{
|
|
qsort( (void*) pModes,
|
|
(size_t) iModes,
|
|
(size_t) sizeof(DEVMODE),
|
|
( int (_cdecl*)(const void*,const void*) ) CompareDevmodes );
|
|
|
|
pCurrentdm = NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// For each devmode, add res/color to menu.
|
|
// Make a submenu of frequencies for each res/color
|
|
//
|
|
|
|
for (n=0; n < iModes; n++)
|
|
{
|
|
PDEVMODE pDM = &pModes[n];
|
|
|
|
//
|
|
// Tested successfully or might require restart
|
|
//
|
|
|
|
if ( ( (CDSTEST(pDM) == DISP_CHANGE_SUCCESSFUL) ||
|
|
(fShowModesThatNeedRestart && (CDSTEST(pDM) == DISP_CHANGE_RESTART)) ) &&
|
|
|
|
( !fShowTestedModes || fGoodMode(pDM) ) )
|
|
{
|
|
|
|
|
|
//
|
|
// Check for change in the major/minor sort item
|
|
// *only after we 'initialize' firstmode below
|
|
//
|
|
|
|
if (FirstMode == -1)
|
|
{
|
|
|
|
//
|
|
// First time thru, initialize FirstMode,counter
|
|
//
|
|
|
|
FirstMode = n;
|
|
FreqCount=0;
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
if( BPP(&pModes[FirstMode]) != BPP(pDM) )
|
|
{
|
|
bMajorChange = fSortByBPP;
|
|
bMinorChange = !fSortByBPP;
|
|
}
|
|
|
|
if( ( XRES(&pModes[FirstMode]) != XRES(pDM) ) ||
|
|
( YRES(&pModes[FirstMode]) != YRES(pDM) ) )
|
|
{
|
|
bMajorChange |= !fSortByBPP;
|
|
bMinorChange |= fSortByBPP;
|
|
}
|
|
|
|
|
|
//
|
|
// The BPP and/or the Resolution changed.
|
|
//
|
|
|
|
if ( bMajorChange || bMinorChange )
|
|
{
|
|
|
|
//
|
|
// Appends a Res/BPP and a submenu if applicable
|
|
//
|
|
|
|
HandleFreqMenu(FreqCount,ResCounter,FirstMode);
|
|
ResCounter++;
|
|
|
|
//
|
|
// Need a separator when major sort item changes
|
|
//
|
|
|
|
if ( bMajorChange )
|
|
{
|
|
AppendMenu(ModeMenu,MF_SEPARATOR,0,NULL);
|
|
ResCounter++;
|
|
}
|
|
|
|
|
|
//
|
|
// n is first mode for the new res/bpp
|
|
// reset counter, flags
|
|
//
|
|
|
|
FirstMode = n;
|
|
FreqCount= 0;
|
|
bMajorChange = FALSE;
|
|
bMinorChange = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Fill in fields for this mode; inc freqcount
|
|
//
|
|
|
|
|
|
MENUITEM( pDM ) = MENU_RES+n;
|
|
FREQMENU( pDM ) = ResCounter;
|
|
FreqCount++;
|
|
|
|
|
|
//
|
|
// ALLMODEMENU - Force menu append every time
|
|
//
|
|
|
|
if (FreqMenuLocation == IDD_ALLMODEMENU)
|
|
{
|
|
bMinorChange = TRUE;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
} // end for
|
|
|
|
|
|
//
|
|
// NO VALID MODES!!! Certainly the current mode should be valid. Make
|
|
// this mode VALID. Setup FreqCount, FirstMode for the last HandleFreqMenu
|
|
//
|
|
|
|
if (FirstMode == -1)
|
|
{
|
|
DEVMODE DisplayMode;
|
|
|
|
DisplayMode.dmSize= sizeof(DEVMODE);
|
|
GetCurrentDevMode(&DisplayMode);
|
|
|
|
for (n=0; CompareDevmodes(&DisplayMode,&pModes[n]) != 0; n++ )
|
|
{
|
|
}
|
|
|
|
VALIDMODE(&pModes[n]) = MODE_BESTHZ;
|
|
FirstMode = n;
|
|
FreqCount = 1;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Handle the FreqMenu for the last Res/BPP.
|
|
//
|
|
|
|
HandleFreqMenu(FreqCount,ResCounter,FirstMode);
|
|
|
|
|
|
//
|
|
// Update menu checks; mode status
|
|
//
|
|
|
|
CheckMenuItemCurrentMode();
|
|
|
|
|
|
//
|
|
// Put Hz menu next to current mode, or at the bottom
|
|
//
|
|
|
|
if (FreqMenuLocation == IDD_ONEMENUMOBILE)
|
|
{
|
|
MENUITEMINFO mii;
|
|
|
|
mii.fMask = MIIM_SUBMENU;
|
|
mii.hSubMenu = FreqMenu[FREQMENU(pCurrentdm)];
|
|
SetMenuItemInfo(ModeMenu, FREQMENU(pCurrentdm), MF_BYPOSITION, &mii);
|
|
}
|
|
|
|
else
|
|
{
|
|
|
|
if (FreqMenuLocation == IDD_ONEMENUBOTTOM)
|
|
{
|
|
PTCHAR szRefRate;
|
|
UINT flags=MF_POPUP;
|
|
|
|
szRefRate = GetResourceString(IDS_REFRESHRATE);
|
|
|
|
if ( !FreqMenu[FREQMENU(pCurrentdm)] )
|
|
{
|
|
flags = MF_GRAYED;
|
|
}
|
|
|
|
AppendMenu(ModeMenu,MF_SEPARATOR,0,NULL);
|
|
AppendMenu(ModeMenu, flags,
|
|
(UINT)FreqMenu[FREQMENU(pCurrentdm)],
|
|
szRefRate);
|
|
|
|
LocalFree(szRefRate);
|
|
}
|
|
}
|
|
|
|
#ifdef MAINWITHMODE
|
|
|
|
//
|
|
// Add main menu to bottom of mode menu. These menu
|
|
// items come from MainMenu as defined in .rc file
|
|
//
|
|
|
|
AppendMenu(ModeMenu,MF_SEPARATOR,0,NULL);
|
|
|
|
for (n=0; n < GetMenuItemCount(MainMenu); n++)
|
|
{
|
|
|
|
MENUITEMINFO mii;
|
|
|
|
mii.cbSize = sizeof(mii);
|
|
|
|
mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID;
|
|
|
|
mii.cch = GetMenuString(MainMenu, n, NULL, 0, MF_BYPOSITION) +1;
|
|
|
|
if (mii.dwTypeData = LocalAlloc( LPTR, mii.cch ))
|
|
{
|
|
GetMenuItemInfo(MainMenu, n, MF_BYPOSITION, &mii);
|
|
|
|
AppendMenu(ModeMenu, MF_STRING, mii.wID, mii.dwTypeData);
|
|
|
|
LocalFree(mii.dwTypeData);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
return ModeMenu;
|
|
}
|
|
|
|
|
|
//
|
|
//********************************************************************
|
|
//
|
|
// BuildDevmodeList( )
|
|
//
|
|
// Enumerate all devmodes into an array; sort them, and filter
|
|
// out duplicate modes, 4bpp modes (if there is an 8bpp mode at
|
|
// the same resolution), and modes with Y Resolution < 400 pixels.
|
|
//
|
|
//********************************************************************
|
|
//
|
|
|
|
BOOL BuildDevmodeList( )
|
|
{
|
|
|
|
DEVMODE DisplayMode; // temporary devmode storage
|
|
int n; // counter
|
|
|
|
|
|
DisplayMode.dmSize= sizeof(DEVMODE);
|
|
|
|
//
|
|
// Find the number of modes known by driver
|
|
//
|
|
|
|
for( iModes=0; EnumDisplaySettings(NULL, iModes, &DisplayMode); iModes++)
|
|
{
|
|
}
|
|
|
|
|
|
//
|
|
// Get space for all modes
|
|
//
|
|
|
|
pModes= (PDEVMODE) GlobalAlloc( GPTR, iModes*sizeof(DEVMODE) );
|
|
|
|
if( !pModes )
|
|
{
|
|
DestroyModeMenu( FALSE, FALSE );
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Get all display modes into the pModes array
|
|
//
|
|
|
|
for( n=0; n<iModes; n++ )
|
|
{
|
|
pModes[n].dmSize= sizeof(DEVMODE);
|
|
|
|
//
|
|
// Get next mode into next spot in pModes
|
|
//
|
|
|
|
EnumDisplaySettings( NULL, n, &pModes[n] );
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// sort them according to QF_SORTBYBPP :
|
|
// (1) BPP X Y HZ or (2) X Y BPP HZ
|
|
//
|
|
|
|
qsort( (void*) pModes,
|
|
(size_t) iModes,
|
|
(size_t) sizeof(DEVMODE),
|
|
( int (_cdecl*)(const void*,const void*) ) CompareDevmodes );
|
|
|
|
|
|
//
|
|
// Filter out any duplicate devmodes return by the driver
|
|
// and any modes with y resolution < 400 pixels
|
|
//
|
|
|
|
if (iModes > 1 )
|
|
{
|
|
|
|
for (n=0; n+1 < iModes; )
|
|
{
|
|
|
|
if (YRES(&pModes[n]) < 400)
|
|
{
|
|
iModes--;
|
|
MoveMemory( &pModes[n],
|
|
&pModes[n+1],
|
|
(iModes-n)*sizeof(DEVMODE) );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If consecutive devmodes are identical, then copy the next
|
|
// one over the dup and decrement iModes (# of devmodes).
|
|
//
|
|
|
|
while ( CompareDevmodes(&pModes[n],&pModes[n+1]) == 0 )
|
|
{
|
|
//
|
|
// Don't go past the last devmode
|
|
//
|
|
|
|
if (n+2 < iModes--)
|
|
{
|
|
MoveMemory( &pModes[n],
|
|
&pModes[n+1],
|
|
(iModes-n)*sizeof(DEVMODE) );
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
n++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Check CDS return value for all modes and eliminate all 4bpp
|
|
// modes that have a corresponding 8bpp mode at the same res
|
|
//
|
|
|
|
for (n=0; n < iModes; n++)
|
|
{
|
|
|
|
CDSTEST(&pModes[n]) = (WORD)ChangeDisplaySettings( &pModes[n], CDS_TEST );
|
|
|
|
//
|
|
// Filter out all 4BPP modes that have an 8BPP mode at the same resolution
|
|
//
|
|
|
|
if (BPP(&pModes[n])==8)
|
|
{
|
|
INT i;
|
|
|
|
for (i=0; i < n; )
|
|
{
|
|
|
|
if ( (BPP (&pModes[i]) == 4) &&
|
|
(XRES(&pModes[n]) == XRES(&pModes[i])) &&
|
|
(YRES(&pModes[n]) == YRES(&pModes[i])) )
|
|
{
|
|
iModes--;
|
|
MoveMemory( &pModes[i],
|
|
&pModes[i+1],
|
|
(iModes-i)*sizeof(DEVMODE) );
|
|
n--;
|
|
}
|
|
else
|
|
{
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Get modeflags from registry or zero out modeflags[]
|
|
//
|
|
|
|
GetDevmodeFlags();
|
|
|
|
//
|
|
// Call GetModeMenu to put all strings/popups in place
|
|
//
|
|
|
|
GetModeMenu( FALSE );
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
//********************************************************************
|
|
//
|
|
// DoProperties( )
|
|
//
|
|
// Calls the control panel applet to show 'Display Properties'
|
|
// specifically the display settings
|
|
//
|
|
//********************************************************************
|
|
//
|
|
|
|
void DoProperties( )
|
|
{
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
|
|
|
|
GetStartupInfo( &si );
|
|
|
|
|
|
//
|
|
// Start it up.
|
|
//
|
|
|
|
CreateProcess(NULL, DISPLAYPROPERTIES, NULL, NULL, FALSE,
|
|
0, NULL, NULL, &si, &pi);
|
|
|
|
|
|
//
|
|
// Dont care what wait return value is, but we want
|
|
// to 'disable' tray icon for a minute or until the
|
|
// user kills desk.cpl
|
|
//
|
|
|
|
WaitForSingleObject( pi.hProcess, 60*1000 );
|
|
|
|
|
|
CloseHandle ( pi.hThread );
|
|
CloseHandle ( pi.hProcess );
|
|
}
|
|
|
|
|
|
//
|
|
//********************************************************************
|
|
//
|
|
// AppWndProc(HWND, UINT, WPARAM, LPARAM)
|
|
//
|
|
// Main window proc to process messages
|
|
//
|
|
//********************************************************************
|
|
//
|
|
|
|
LONG CALLBACK AppWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
|
|
{
|
|
|
|
POINT pt; // Get cursor pos for the menu placement
|
|
|
|
|
|
switch (msg)
|
|
{
|
|
|
|
case WM_CREATE:
|
|
|
|
//
|
|
// Add icon to tray next to time
|
|
//
|
|
|
|
TrayMessage(hwnd, NIM_ADD, TRAY_ID, AppIcon);
|
|
|
|
break;
|
|
|
|
|
|
case WM_DESTROY:
|
|
|
|
//
|
|
// Remove icon from tray.
|
|
//
|
|
|
|
TrayMessage(hwnd, NIM_DELETE, TRAY_ID, NULL );
|
|
|
|
PostQuitMessage(0);
|
|
|
|
break;
|
|
|
|
|
|
case WM_SETTINGCHANGE:
|
|
case WM_DISPLAYCHANGE:
|
|
|
|
//
|
|
// Something else, like desktop cpl, changed display
|
|
// settings. Need to rebuild menu to reflect change.
|
|
// Reset pCurrentdm as index in pMOdes
|
|
//
|
|
|
|
if (!Waiting)
|
|
{
|
|
pCurrentdm = NULL;
|
|
CheckMenuItemCurrentMode();
|
|
|
|
|
|
//
|
|
// Rebuild menu & change tooltip text.
|
|
//
|
|
|
|
VALIDMODE(pCurrentdm) = MODE_BESTHZ;
|
|
DestroyModeMenu(TRUE,FALSE);
|
|
TrayMessage(hwnd, NIM_MODIFY, TRAY_ID, AppIcon);
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case WM_DEVICECHANGE:
|
|
|
|
if (wParam == DBT_CONFIGCHANGED ||
|
|
wParam == DBT_MONITORCHANGE)
|
|
{
|
|
|
|
//
|
|
// Will need a new menu; clear devmode flags
|
|
//
|
|
|
|
DestroyModeMenu( TRUE, TRUE );
|
|
SetDevmodeFlags( TRUE );
|
|
|
|
}
|
|
break;
|
|
|
|
|
|
case WM_COMMAND:
|
|
{
|
|
|
|
switch (LOWORD(wParam))
|
|
{
|
|
|
|
case MENU_CLOSE:
|
|
|
|
PostMessage(hwnd, WM_CLOSE, 0, 0);
|
|
|
|
break;
|
|
|
|
case MENU_PROPERTIES:
|
|
|
|
//
|
|
// Start control panel applet
|
|
//
|
|
|
|
DoProperties();
|
|
|
|
break;
|
|
|
|
|
|
case MENU_ABOUT:
|
|
|
|
//
|
|
// Show a generic about box
|
|
//
|
|
|
|
MsgBox(IDS_ABOUT, 0, MB_OK);
|
|
|
|
break;
|
|
|
|
|
|
case MENU_OPTIONS:
|
|
|
|
//
|
|
// After showing options dlg box, show mode menu again
|
|
//
|
|
|
|
DialogBox(hInstApp, MAKEINTRESOURCE(Options),NULL,OptionsDlgProc);
|
|
SetTimer(hwnd, TRAY_ID, 10, NULL);
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
{
|
|
|
|
//
|
|
// Change devmode to pModes[OffsetPdev]
|
|
//
|
|
|
|
INT OffsetPdev;
|
|
|
|
//
|
|
// The menu item is an offset from MENU_RES
|
|
// of the selected item.
|
|
//
|
|
|
|
OffsetPdev= LOWORD(wParam) - MENU_RES;
|
|
|
|
|
|
//
|
|
// Check that the offset is within range
|
|
//
|
|
|
|
if( OffsetPdev >= 0 && OffsetPdev < iModes )
|
|
{
|
|
|
|
//
|
|
// if different from current devmode then change it
|
|
//
|
|
|
|
if ( CompareDevmodes( &pModes[OffsetPdev], pCurrentdm) )
|
|
{
|
|
SetMode(hwnd, OffsetPdev);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
case WM_TIMER:
|
|
|
|
//
|
|
// Left click was not a double-click
|
|
//
|
|
|
|
KillTimer(hwnd, TRAY_ID);
|
|
GetCursorPos(&pt);
|
|
SetForegroundWindow(hwnd);
|
|
|
|
//
|
|
// Create and/or Get resolutions menu
|
|
//
|
|
|
|
TrackPopupMenu(GetModeMenu( FALSE ), TPM_LEFTBUTTON,
|
|
pt.x, pt.y, 0, hwnd, NULL);
|
|
|
|
break;
|
|
|
|
|
|
case TRAY_MSG:
|
|
{
|
|
|
|
//
|
|
// No messages processed while waiting on
|
|
// a dlg/msg box to return
|
|
//
|
|
|
|
if (!Waiting)
|
|
{
|
|
|
|
switch (lParam)
|
|
{
|
|
case WM_RBUTTONUP:
|
|
|
|
//
|
|
// Properties, about, Exit
|
|
//
|
|
|
|
SetForegroundWindow(hwnd);
|
|
GetCursorPos(&pt);
|
|
|
|
TrackPopupMenu(MainMenu, TPM_RIGHTBUTTON,
|
|
pt.x, pt.y, 0, hwnd, NULL);
|
|
|
|
break;
|
|
|
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
//
|
|
// Resolutions menu
|
|
//
|
|
|
|
SetTimer(hwnd, TRAY_ID, GetDoubleClickTime()+10, NULL);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_LBUTTONDBLCLK:
|
|
|
|
//
|
|
// start control panel applet
|
|
//
|
|
|
|
KillTimer(hwnd, TRAY_ID);
|
|
DoProperties();
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return DefWindowProc(hwnd,msg,wParam,lParam);
|
|
|
|
}
|
|
|
|
|
|
//
|
|
//********************************************************************
|
|
//
|
|
// MsgBox(int, UINT, UINT)
|
|
//
|
|
// Generic messagebox function that can print a value into
|
|
// a format string
|
|
//
|
|
//********************************************************************
|
|
//
|
|
|
|
int MsgBox(int id, UINT value, UINT flags)
|
|
{
|
|
|
|
PTCHAR msgboxtext=NULL; // message box body text
|
|
INT ret = 0;
|
|
MSGBOXPARAMS mb;
|
|
|
|
|
|
//
|
|
// Ignore tray clicks while msgbox is up, and
|
|
// Show at least an OK button.
|
|
//
|
|
|
|
Waiting = TRUE;
|
|
if (flags == 0)
|
|
{
|
|
flags = MB_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// Can print a value into a format string, if value!=0.
|
|
//
|
|
|
|
if (value)
|
|
{
|
|
PTCHAR msgboxfmt; // body test format
|
|
|
|
if (msgboxfmt = GetResourceString ( id ))
|
|
{
|
|
if (msgboxtext = LocalAlloc ( LPTR, sizeof(TCHAR)*
|
|
(lstrlen(msgboxfmt)+INT_FORMAT_TO_5_DIGITS+1)))
|
|
{
|
|
wsprintf(msgboxtext,msgboxfmt,value);
|
|
}
|
|
|
|
LocalFree( msgboxfmt );
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
msgboxtext = GetResourceString ( id );
|
|
}
|
|
|
|
|
|
if (msgboxtext)
|
|
{
|
|
|
|
mb.cbSize = sizeof(mb);
|
|
mb.hwndOwner = NULL;
|
|
mb.hInstance = hInstApp;
|
|
mb.lpszText = msgboxtext;
|
|
mb.lpszCaption = szAppName;
|
|
mb.dwStyle = flags | MB_USERICON;
|
|
mb.lpszIcon = szAppName;
|
|
mb.dwContextHelpId = 0;
|
|
mb.lpfnMsgBoxCallback = NULL;
|
|
mb.dwLanguageId = 0;
|
|
|
|
|
|
//
|
|
// Special API for the about box. otherwise, use Messageboxindirect
|
|
//
|
|
|
|
if (id == IDS_ABOUT)
|
|
{
|
|
ret = ShellAbout(mb.hwndOwner, mb.lpszCaption, mb.lpszText, AppIcon);
|
|
}
|
|
|
|
else
|
|
{
|
|
ret = MessageBoxIndirect(&mb);
|
|
}
|
|
|
|
|
|
//
|
|
// Free string memory; start processing tray msgs again
|
|
//
|
|
|
|
LocalFree( msgboxtext );
|
|
}
|
|
|
|
Waiting = FALSE;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
//********************************************************************
|
|
//
|
|
// WinMain
|
|
//
|
|
//********************************************************************
|
|
//
|
|
|
|
int NEAR PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
|
|
{
|
|
WNDCLASS cls;
|
|
MSG msg;
|
|
HWND hwnd;
|
|
|
|
|
|
hInstApp = hInst;
|
|
szAppName = GetResourceString( IDS_TITLE );
|
|
|
|
|
|
//
|
|
// App is already running. Do not start a 2nd instance
|
|
//
|
|
|
|
if ( FindWindow( szAppName, szAppName ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
AppIcon = LoadIcon(hInst,szAppName);
|
|
|
|
|
|
//
|
|
// Register a class for the main application window
|
|
//
|
|
|
|
cls.lpszClassName = szAppName;
|
|
cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
|
cls.hInstance = hInstApp;
|
|
cls.hIcon = AppIcon;
|
|
cls.hCursor = LoadCursor(NULL,IDC_ARROW);
|
|
cls.lpszMenuName = szAppName;
|
|
cls.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
|
|
cls.lpfnWndProc = (WNDPROC)AppWndProc;
|
|
cls.cbWndExtra = 0;
|
|
cls.cbClsExtra = 0;
|
|
|
|
if (!RegisterClass(&cls))
|
|
return FALSE;
|
|
|
|
hwnd = CreateWindow(szAppName,
|
|
szAppName,
|
|
WS_OVERLAPPEDWINDOW,
|
|
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
|
|
NULL, NULL,
|
|
hInstApp, NULL);
|
|
|
|
|
|
//
|
|
// Properties, about, exit - properties is the default
|
|
//
|
|
|
|
MainMenu = GetSubMenu(GetMenu(hwnd), 0);
|
|
SetMenuDefaultItem(MainMenu,MENU_PROPERTIES,MF_BYCOMMAND);
|
|
|
|
|
|
//
|
|
// Get flags from registry and build the modemenu
|
|
// from scratch.
|
|
//
|
|
|
|
GetQuickResFlags( );
|
|
|
|
if (!BuildDevmodeList())
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Update tray tooltip to be current resolution
|
|
//
|
|
|
|
TrayMessage( hwnd, NIM_MODIFY, TRAY_ID, AppIcon );
|
|
|
|
|
|
//
|
|
// Polling messages from event queue
|
|
//
|
|
|
|
while (GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
|
|
//
|
|
// write flags to registry
|
|
//
|
|
|
|
SetQuickResFlags( );
|
|
if (fRememberModes)
|
|
{
|
|
SetDevmodeFlags( FALSE );
|
|
}
|
|
|
|
SetRegistryValue(IDS_REGBPPVALUE, REG_DWORD,
|
|
&( BPP(pCurrentdm) ), sizeof(DWORD) );
|
|
|
|
|
|
//
|
|
// Free up dynamically allocated globals.
|
|
//
|
|
|
|
LocalFree ( szAppName );
|
|
LocalFree ( pModes );
|
|
|
|
return msg.wParam;
|
|
}
|
|
|
|
|
|
//
|
|
//********************************************************************
|
|
//
|
|
// TrayMessage (HWND, DWORD, UINT, HICON )
|
|
//
|
|
// Add/remove icon to/from tray next to the time
|
|
//
|
|
//********************************************************************
|
|
//
|
|
|
|
BOOL TrayMessage(HWND hwnd, DWORD msg, UINT id, HICON hIcon )
|
|
{
|
|
|
|
NOTIFYICONDATA tnd;
|
|
PTCHAR Res;
|
|
PTCHAR Hz;
|
|
|
|
tnd.cbSize = sizeof(NOTIFYICONDATA);
|
|
tnd.hWnd = hwnd;
|
|
tnd.uID = id;
|
|
|
|
tnd.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;
|
|
tnd.uCallbackMessage = TRAY_MSG;
|
|
tnd.hIcon = hIcon;
|
|
|
|
|
|
//
|
|
// Changing tooltip text to match current resolution
|
|
// (Make sure pCurrentdm is valid / not NULL.
|
|
//
|
|
|
|
if (msg == NIM_MODIFY)
|
|
{
|
|
if (pCurrentdm)
|
|
{
|
|
GetModeName(pCurrentdm, &Res, &Hz);
|
|
|
|
wsprintf(tnd.szTip,TEXT("%s%s"),Res,Hz);
|
|
|
|
LocalFree(Res);
|
|
LocalFree(Hz);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Adding the tray icon - Current devmode
|
|
// is not known so use AppName as tip
|
|
//
|
|
|
|
else
|
|
{
|
|
wsprintf(tnd.szTip, szAppName);
|
|
}
|
|
|
|
return Shell_NotifyIcon( msg, &tnd );
|
|
}
|
|
|
|
|
|
|
|
//
|
|
//*****************************************************************************
|
|
//
|
|
// KeepNewResDlgProc(HWND, UINT, UINT, LONG )
|
|
//
|
|
// User must enter Yes to keep new res, or we default back to the old res.
|
|
//
|
|
//*****************************************************************************
|
|
//
|
|
|
|
UINT FAR PASCAL KeepNewResDlgProc(HWND hDlg, UINT message, UINT wParam, LONG lParam)
|
|
{
|
|
|
|
static int NOTimeOut; // countdown to 0
|
|
|
|
|
|
switch (message)
|
|
{
|
|
|
|
case WM_INITDIALOG: // initialize values and focus
|
|
|
|
{
|
|
|
|
//
|
|
// Initialize values and focus
|
|
//
|
|
|
|
PTCHAR NewResString; // user friendly name for devmode
|
|
PTCHAR NewHzString; // and frequency
|
|
PTCHAR szAt;
|
|
DEVMODE dm;
|
|
|
|
|
|
//
|
|
// Ignore tray messages while waiting for yes/no.
|
|
// Wait KEEP_RES_TIMEOUT seconds.
|
|
//
|
|
|
|
Waiting=TRUE;
|
|
|
|
|
|
//
|
|
// Get current devmode
|
|
//
|
|
|
|
GetCurrentDevMode( &dm );
|
|
|
|
|
|
//
|
|
// Get user friendly strings and concatenate them
|
|
//
|
|
|
|
szAt = GetResourceString ( IDS_AT );
|
|
|
|
GetModeName( &dm, &NewResString, &NewHzString);
|
|
|
|
if ( szAt && NewResString && NewHzString )
|
|
{
|
|
|
|
PTCHAR TotalString;
|
|
|
|
if (TotalString = LocalAlloc ( LPTR, sizeof(TCHAR)*
|
|
( lstrlen(NewResString)+
|
|
lstrlen(NewHzString)+
|
|
lstrlen(szAt)+
|
|
1 ) ))
|
|
{
|
|
lstrcpy(TotalString, NewResString);
|
|
lstrcat(TotalString, szAt);
|
|
lstrcat(TotalString, NewHzString);
|
|
|
|
|
|
//
|
|
// Replace 2nd text item of msgbox
|
|
//
|
|
|
|
SetDlgItemText(hDlg, IDTEXT2, TotalString);
|
|
|
|
LocalFree ( TotalString );
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// LocalFree handles NULL pointers gracefully (does nothing)
|
|
//
|
|
|
|
LocalFree ( szAt );
|
|
LocalFree ( NewResString );
|
|
LocalFree ( NewHzString );
|
|
|
|
|
|
//
|
|
// Set timeout length and start waiting
|
|
//
|
|
|
|
NOTimeOut=KEEP_RES_TIMEOUT;
|
|
SetTimer(hDlg,IDD_COUNTDOWN,1000,NULL);
|
|
|
|
return (TRUE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
case WM_TIMER:
|
|
|
|
{
|
|
PTCHAR NoTextFmt; // "NO: %d"
|
|
PTCHAR NoText; // e.g. "NO: 15"
|
|
|
|
//
|
|
// Still counting down
|
|
//
|
|
|
|
if ( NOTimeOut >= 0 )
|
|
{
|
|
//
|
|
// Get format string for NO Button.
|
|
// Write it to NoText String and to dlg box
|
|
//
|
|
|
|
NoTextFmt = GetResourceString ( IDS_NOTEXT );
|
|
|
|
if (NoTextFmt)
|
|
{
|
|
NoText = LocalAlloc ( LPTR, sizeof(TCHAR)*
|
|
( lstrlen(NoTextFmt)+1 ) );
|
|
wsprintf(NoText, NoTextFmt, NOTimeOut--);
|
|
|
|
SetDlgItemText(hDlg, IDNO, NoText);
|
|
|
|
LocalFree ( NoTextFmt );
|
|
LocalFree ( NoText );
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
//
|
|
// Give up on the user - return NO
|
|
//
|
|
|
|
KillTimer(hDlg, IDD_COUNTDOWN);
|
|
SendMessage(hDlg, WM_COMMAND, IDNO, 0);
|
|
}
|
|
|
|
return (TRUE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case WM_COMMAND:
|
|
|
|
//
|
|
// Start processing tray messages again
|
|
//
|
|
|
|
Waiting=FALSE;
|
|
|
|
switch (LOWORD(wParam))
|
|
|
|
{
|
|
|
|
//
|
|
// return value based on the button pressed
|
|
//
|
|
|
|
case IDYES :
|
|
case IDNO :
|
|
case IDABORT :
|
|
case IDCANCEL :
|
|
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
return (TRUE);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
} // switch (wParam)
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
} // switch (message)
|
|
|
|
|
|
return (FALSE); // Didn't process a message
|
|
|
|
|
|
} // KeepNewResDlgProc()
|
|
|
|
|
|
|
|
//
|
|
//*****************************************************************************
|
|
//
|
|
// OptionsDlgProc(HWND, UINT, UINT, LONG )
|
|
//
|
|
//
|
|
//
|
|
//*****************************************************************************
|
|
//
|
|
|
|
UINT FAR PASCAL OptionsDlgProc(HWND hDlg, UINT message, UINT wParam, LONG lParam)
|
|
{
|
|
|
|
switch (message)
|
|
{
|
|
|
|
case WM_INITDIALOG:
|
|
|
|
//
|
|
// Stop processing tray messages; check buttons properly
|
|
//
|
|
|
|
Waiting = TRUE;
|
|
|
|
CheckRadioButton(hDlg,IDD_SORT_RES,IDD_SORT_BPP,
|
|
(fSortByBPP ? IDD_SORT_BPP : IDD_SORT_RES) );
|
|
CheckRadioButton(hDlg,IDD_SUBMENUS,IDD_ALLMODEMENU, FreqMenuLocation );
|
|
|
|
CheckDlgButton(hDlg, IDD_UPDATEREG, fUpdateReg );
|
|
CheckDlgButton(hDlg, IDD_REMMODES, fRememberModes );
|
|
CheckDlgButton(hDlg, IDD_RESTARTREQ, fShowModesThatNeedRestart );
|
|
CheckDlgButton(hDlg, IDD_SHOWTESTED, fShowTestedModes );
|
|
|
|
return TRUE;
|
|
break;
|
|
|
|
|
|
case WM_COMMAND:
|
|
|
|
|
|
switch (LOWORD(wParam))
|
|
|
|
{
|
|
|
|
//
|
|
// Update buttons : sorting by BPP or Res?
|
|
//
|
|
|
|
case IDD_SORT_RES:
|
|
case IDD_SORT_BPP:
|
|
CheckRadioButton(hDlg,IDD_SORT_RES,IDD_SORT_BPP,LOWORD(wParam));
|
|
return TRUE;
|
|
break;
|
|
|
|
//
|
|
// Update buttons : where to display freq menus?
|
|
//
|
|
|
|
case IDD_SUBMENUS:
|
|
case IDD_ONEMENUMOBILE:
|
|
case IDD_ONEMENUBOTTOM:
|
|
case IDD_ALLMODEMENU:
|
|
CheckRadioButton(hDlg,IDD_SUBMENUS,IDD_ALLMODEMENU,LOWORD(wParam));
|
|
return TRUE;
|
|
break;
|
|
|
|
|
|
//
|
|
// Clear all registry remembered settings
|
|
// Make user verify he did this on purpose
|
|
//
|
|
|
|
case IDD_CLEARREG:
|
|
if (MsgBox(IDS_CLEARREG,
|
|
0,
|
|
MB_OKCANCEL | MB_ICONEXCLAMATION | MB_TASKMODAL)
|
|
== IDOK)
|
|
{
|
|
SetDevmodeFlags(TRUE);
|
|
}
|
|
|
|
VALIDMODE(pCurrentdm) = MODE_BESTHZ;
|
|
DestroyModeMenu( TRUE, FALSE);
|
|
|
|
return TRUE;
|
|
break;
|
|
|
|
|
|
//
|
|
// XOR QuickResFlags on and off
|
|
//
|
|
|
|
case IDD_UPDATEREG:
|
|
QuickResFlags ^= QF_UPDATEREG;
|
|
return TRUE;
|
|
break;
|
|
|
|
case IDD_REMMODES:
|
|
QuickResFlags ^= QF_REMMODES;
|
|
return TRUE;
|
|
break;
|
|
|
|
case IDD_RESTARTREQ:
|
|
QuickResFlags ^= QF_SHOWRESTART;
|
|
DestroyModeMenu( TRUE, FALSE);
|
|
return TRUE;
|
|
break;
|
|
|
|
case IDD_SHOWTESTED:
|
|
QuickResFlags ^= QF_SHOWTESTED;
|
|
DestroyModeMenu( TRUE, FALSE);
|
|
return TRUE;
|
|
break;
|
|
|
|
case IDOK:
|
|
|
|
//
|
|
// If sort order has changed, update it & destroy,
|
|
// resort, and rebuild old menu.
|
|
//
|
|
|
|
if ( (IsDlgButtonChecked (hDlg, IDD_SORT_RES) && fSortByBPP) ||
|
|
(IsDlgButtonChecked (hDlg, IDD_SORT_BPP) && !fSortByBPP) )
|
|
{
|
|
QuickResFlags ^= QF_SORT_BYBPP;
|
|
DestroyModeMenu( TRUE, TRUE );
|
|
}
|
|
|
|
|
|
//
|
|
// see if FreqMenuLocation has changed
|
|
//
|
|
|
|
if (!IsDlgButtonChecked (hDlg, FreqMenuLocation))
|
|
{
|
|
//
|
|
// Freq menu location has changed; update & destroy old menu
|
|
//
|
|
|
|
if (IsDlgButtonChecked (hDlg, IDD_SUBMENUS))
|
|
{
|
|
FreqMenuLocation = IDD_SUBMENUS;
|
|
}
|
|
else
|
|
{
|
|
if (IsDlgButtonChecked (hDlg, IDD_ONEMENUMOBILE))
|
|
{
|
|
FreqMenuLocation = IDD_ONEMENUMOBILE;
|
|
}
|
|
else
|
|
{
|
|
if (IsDlgButtonChecked (hDlg, IDD_ONEMENUBOTTOM))
|
|
{
|
|
FreqMenuLocation = IDD_ONEMENUBOTTOM;
|
|
}
|
|
else
|
|
{
|
|
if (IsDlgButtonChecked (hDlg, IDD_ALLMODEMENU))
|
|
{
|
|
FreqMenuLocation = IDD_ALLMODEMENU;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Rebuild menu without resorting modes
|
|
//
|
|
|
|
DestroyModeMenu( TRUE, FALSE);
|
|
}
|
|
|
|
|
|
//
|
|
// No break after IDOK, by design.
|
|
// IDOK AND IDCANCEL : start processing tray clicks,
|
|
// and return ok/cancel as return value.
|
|
//
|
|
|
|
case IDCANCEL :
|
|
|
|
Waiting = FALSE;
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
return TRUE;
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
} // switch (wParam)
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
} // switch (message)
|
|
|
|
|
|
return FALSE; // Didn't process a message
|
|
|
|
|
|
} // OptionsDlgProc()
|