From 6154b46bef5af2fb0dd9ce7842afdc699b58814f Mon Sep 17 00:00:00 2001 From: Rein Klazes Date: Tue, 22 Nov 2005 14:56:11 +0000 Subject: [PATCH] GetSystemMetrics fixes with corresponding tests. --- dlls/user/sysparams.c | 75 +++++++++--- dlls/user/tests/sysparams.c | 225 +++++++++++++++++++++++++++++++++++- 2 files changed, 280 insertions(+), 20 deletions(-) diff --git a/dlls/user/sysparams.c b/dlls/user/sysparams.c index a425f983b02..9bb6a32df4c 100644 --- a/dlls/user/sysparams.c +++ b/dlls/user/sysparams.c @@ -330,8 +330,11 @@ static NONCLIENTMETRICSW nonclient_metrics = { 0 } /* lfMessageFont */ }; +/* some additional non client metric info */ +static TEXTMETRICW tmMenuFont; +static UINT CaptionFontAvCharWidth; + static SIZE icon_size = { 32, 32 }; -static SIZE scroll_height = { 16, 16 }; #define NUM_SYS_COLORS (COLOR_MENUBAR+1) @@ -476,6 +479,27 @@ static void SYSPARAMS_NonClientMetrics32ATo32W( const NONCLIENTMETRICSA* lpnm32A SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfMessageFont, &lpnm32W->lfMessageFont ); } +/* get text metrics and/or "average" char width of the specified logfont + * for the specified dc */ +static void get_text_metr_size( HDC hdc, LOGFONTW *plf, TEXTMETRICW * ptm, UINT *psz) +{ + HFONT hfont, hfontsav; + TEXTMETRICW tm; + if( !ptm) ptm = &tm; + hfont = CreateFontIndirectW( plf); + if( !hfont || ( hfontsav = SelectObject( hdc, hfont)) == NULL ) { + ptm->tmHeight = -1; + if( psz) *psz = 10; + if( hfont) DeleteObject( hfont); + return; + } + GetTextMetricsW( hdc, ptm); + if( psz) + if( !(*psz = GdiGetCharDimensions( hdc, ptm, NULL))) + *psz = 10; + SelectObject( hdc, hfontsav); + DeleteObject( hfont); +} /*********************************************************************** * get_volatile_regkey @@ -933,7 +957,7 @@ static void load_nonclient_metrics(void) nonclient_metrics.iBorderWidth = get_reg_metric(hkey, METRICS_BORDERWIDTH_VALNAME, 1); if( nonclient_metrics.iBorderWidth < 1) nonclient_metrics.iBorderWidth = 1; nonclient_metrics.iScrollWidth = get_reg_metric(hkey, METRICS_SCROLLWIDTH_VALNAME, 16); - nonclient_metrics.iScrollHeight = nonclient_metrics.iScrollWidth; + nonclient_metrics.iScrollHeight = get_reg_metric(hkey, METRICS_SCROLLHEIGHT_VALNAME, 16); /* size of the normal caption buttons */ nonclient_metrics.iCaptionHeight = get_reg_metric(hkey, METRICS_CAPTIONHEIGHT_VALNAME, 18); @@ -993,8 +1017,10 @@ static void load_nonclient_metrics(void) /* some extra fields not in the nonclient structure */ icon_size.cx = icon_size.cy = get_reg_metric( hkey, METRICS_ICONSIZE_VALNAME, 32 ); - scroll_height.cx = get_reg_metric (hkey, METRICS_SCROLLHEIGHT_VALNAME, nonclient_metrics.iScrollHeight ); - scroll_height.cy = get_reg_metric (hkey, METRICS_SCROLLHEIGHT_VALNAME, nonclient_metrics.iScrollWidth ); + get_text_metr_size( get_display_dc(), &nonclient_metrics.lfMenuFont, + &tmMenuFont, NULL); + get_text_metr_size( get_display_dc(), &nonclient_metrics.lfCaptionFont, + NULL, &CaptionFontAvCharWidth); if (hkey) RegCloseKey( hkey ); spi_loaded[SPI_NONCLIENTMETRICS_IDX] = TRUE; @@ -2329,11 +2355,10 @@ INT WINAPI GetSystemMetrics( INT index ) if (!spi_loaded[SPI_NONCLIENTMETRICS_IDX]) load_nonclient_metrics(); return nonclient_metrics.iScrollWidth; case SM_CYHSCROLL: - if (!spi_loaded[SPI_NONCLIENTMETRICS_IDX]) load_nonclient_metrics(); - return nonclient_metrics.iScrollHeight; + return GetSystemMetrics(SM_CXVSCROLL); case SM_CYCAPTION: if (!spi_loaded[SPI_NONCLIENTMETRICS_IDX]) load_nonclient_metrics(); - return nonclient_metrics.iCaptionHeight + 1; /* for the separator? */ + return nonclient_metrics.iCaptionHeight + 1; case SM_CXBORDER: case SM_CYBORDER: /* SM_C{X,Y}BORDER always returns 1 regardless of 'BorderWidth' value in registry */ @@ -2342,9 +2367,10 @@ INT WINAPI GetSystemMetrics( INT index ) case SM_CYDLGFRAME: return 3; case SM_CYVTHUMB: - return GetSystemMetrics(SM_CXVSCROLL); + if (!spi_loaded[SPI_NONCLIENTMETRICS_IDX]) load_nonclient_metrics(); + return nonclient_metrics.iScrollHeight; case SM_CXHTHUMB: - return GetSystemMetrics(SM_CYHSCROLL); + return GetSystemMetrics(SM_CYVTHUMB); case SM_CXICON: if (!spi_loaded[SPI_NONCLIENTMETRICS_IDX]) load_nonclient_metrics(); return icon_size.cx; @@ -2357,19 +2383,23 @@ INT WINAPI GetSystemMetrics( INT index ) case SM_CYMENU: return GetSystemMetrics(SM_CYMENUSIZE) + 1; case SM_CXFULLSCREEN: - return GetSystemMetrics(SM_CXSCREEN); + /* see the remark for SM_CXMAXIMIZED, at least this formulation is + * correct */ + return GetSystemMetrics( SM_CXMAXIMIZED) - 2 * GetSystemMetrics( SM_CXFRAME); case SM_CYFULLSCREEN: - return GetSystemMetrics(SM_CYSCREEN) - GetSystemMetrics(SM_CYCAPTION); + /* see the remark for SM_CYMAXIMIZED, at least this formulation is + * correct */ + return GetSystemMetrics( SM_CYMAXIMIZED) - GetSystemMetrics( SM_CYMIN); case SM_CYKANJIWINDOW: return 0; case SM_MOUSEPRESENT: return 1; case SM_CYVSCROLL: if (!spi_loaded[SPI_NONCLIENTMETRICS_IDX]) load_nonclient_metrics(); - return scroll_height.cy; + return nonclient_metrics.iScrollHeight; case SM_CXHSCROLL: if (!spi_loaded[SPI_NONCLIENTMETRICS_IDX]) load_nonclient_metrics(); - return scroll_height.cx; + return nonclient_metrics.iScrollHeight; case SM_DEBUG: return 0; case SM_SWAPBUTTON: @@ -2382,9 +2412,11 @@ INT WINAPI GetSystemMetrics( INT index ) case SM_RESERVED4: return 0; case SM_CXMIN: - return 112; /* FIXME */ + if (!spi_loaded[SPI_NONCLIENTMETRICS_IDX]) load_nonclient_metrics(); + return 3 * nonclient_metrics.iCaptionWidth + GetSystemMetrics( SM_CYSIZE) + + 4 * CaptionFontAvCharWidth + 2 * GetSystemMetrics( SM_CXFRAME) + 4; case SM_CYMIN: - return 27; /* FIXME */ + return GetSystemMetrics( SM_CYCAPTION) + 2 * GetSystemMetrics( SM_CYFRAME); case SM_CXSIZE: if (!spi_loaded[SPI_NONCLIENTMETRICS_IDX]) load_nonclient_metrics(); return nonclient_metrics.iCaptionWidth; @@ -2396,7 +2428,7 @@ INT WINAPI GetSystemMetrics( INT index ) return GetSystemMetrics(SM_CXDLGFRAME) + nonclient_metrics.iBorderWidth; case SM_CYFRAME: if (!spi_loaded[SPI_NONCLIENTMETRICS_IDX]) load_nonclient_metrics(); - return GetSystemMetrics(SM_CXDLGFRAME) + nonclient_metrics.iBorderWidth; + return GetSystemMetrics(SM_CYDLGFRAME) + nonclient_metrics.iBorderWidth; case SM_CXMINTRACK: return GetSystemMetrics(SM_CXMIN); case SM_CYMINTRACK: @@ -2460,15 +2492,18 @@ INT WINAPI GetSystemMetrics( INT index ) case SM_CXMINIMIZED: return minimized_metrics.iWidth + 6; case SM_CYMINIMIZED: - return 24; /* FIXME */ + if (!spi_loaded[SPI_NONCLIENTMETRICS_IDX]) load_nonclient_metrics(); + return nonclient_metrics.iCaptionHeight + 6; case SM_CXMAXTRACK: return GetSystemMetrics(SM_CXSCREEN) + 4 + 2 * GetSystemMetrics(SM_CXFRAME); case SM_CYMAXTRACK: return GetSystemMetrics(SM_CYSCREEN) + 4 + 2 * GetSystemMetrics(SM_CYFRAME); case SM_CXMAXIMIZED: + /* FIXME: subtract the width of any vertical application toolbars*/ return GetSystemMetrics(SM_CXSCREEN) + 2 * GetSystemMetrics(SM_CXFRAME); case SM_CYMAXIMIZED: - return GetSystemMetrics(SM_CYSCREEN) + 2 * GetSystemMetrics(SM_CYFRAME); + /* FIXME: subtract the width of any horizontal application toolbars*/ + return GetSystemMetrics(SM_CYSCREEN) + 2 * GetSystemMetrics(SM_CYCAPTION); case SM_NETWORK: return 3; /* FIXME */ case SM_CLEANBOOT: @@ -2481,7 +2516,9 @@ INT WINAPI GetSystemMetrics( INT index ) return ret; case SM_CXMENUCHECK: case SM_CYMENUCHECK: - return 13; + if (!spi_loaded[SPI_NONCLIENTMETRICS_IDX]) load_nonclient_metrics(); + return tmMenuFont.tmHeight <= 0 ? 13 : + ((tmMenuFont.tmHeight + tmMenuFont.tmExternalLeading + 1) / 2) * 2 - 1; case SM_SLOWMACHINE: return 0; /* FIXME: Should check the type of processor */ case SM_MIDEASTENABLED: diff --git a/dlls/user/tests/sysparams.c b/dlls/user/tests/sysparams.c index a4af9f5174f..1d8fbe9822c 100644 --- a/dlls/user/tests/sysparams.c +++ b/dlls/user/tests/sysparams.c @@ -1815,6 +1815,227 @@ static DWORD WINAPI SysParamsThreadFunc( LPVOID lpParam ) return 0; } +/* test calculation of GetSystemMetrics values (mostly) from non client metrics, + * icon metrics and minimized metrics. + */ + +/* copied from wine's GdiGetCharDimensions, which is not available on most + * windows versions */ +static LONG _GdiGetCharDimensions(HDC hdc, LPTEXTMETRICA lptm, LONG *height) +{ + SIZE sz; + static const CHAR alphabet[] = { + 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q', + 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H', + 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0}; + + if(lptm && !GetTextMetricsA(hdc, lptm)) return 0; + + if(!GetTextExtentPointA(hdc, alphabet, 52, &sz)) return 0; + + if (height) *height = sz.cy; + return (sz.cx / 26 + 1) / 2; +} + +/* get text metrics and/or "average" char width of the specified logfont + * for the specified dc */ +void get_text_metr_size( HDC hdc, LOGFONTA *plf, TEXTMETRICA * ptm, UINT *psz) +{ + HFONT hfont, hfontsav; + TEXTMETRICA tm; + if( !ptm) ptm = &tm; + hfont = CreateFontIndirectA( plf); + if( !hfont || ( hfontsav = SelectObject( hdc, hfont)) == NULL ) { + ptm->tmHeight = -1; + if( psz) *psz = 10; + if( hfont) DeleteObject( hfont); + return; + } + GetTextMetricsA( hdc, ptm); + if( psz) + if( !(*psz = _GdiGetCharDimensions( hdc, ptm, NULL))) + *psz = 10; + SelectObject( hdc, hfontsav); + DeleteObject( hfont); +} + +static int gsm_error_ctr; +static UINT smcxsmsize = 999999999; + +#define ok_gsm( i, e)\ +{\ + int exp = (e);\ + int act = GetSystemMetrics( (i));\ + if( exp != act) gsm_error_ctr++;\ + ok( !( exp != act),"GetSystemMetrics(%s): expected %d actual %d\n", #i, exp,act);\ +} +#define ok_gsm_2( i, e1, e2)\ +{\ + int exp1 = (e1);\ + int exp2 = (e2);\ + int act = GetSystemMetrics( (i));\ + if( exp1 != act && exp2 != act) gsm_error_ctr++;\ + ok( !( exp1 != act && exp2 != act), "GetSystemMetrics(%s): expected %d or %d actual %d\n", #i, exp1, exp2, act);\ +} +#define ok_gsm_3( i, e1, e2, e3)\ +{\ + int exp1 = (e1);\ + int exp2 = (e2);\ + int exp3 = (e3);\ + int act = GetSystemMetrics( (i));\ + if( exp1 != act && exp2 != act && exp3 != act) gsm_error_ctr++;\ + ok( !( exp1 != act && exp2 != act && exp3 != act),"GetSystemMetrics(%s): expected %d or %d or %d actual %d\n", #i, exp1, exp2, exp3, act);\ +} + +void test_GetSystemMetrics( void) +{ + TEXTMETRICA tmMenuFont; + UINT IconSpacing, IconVerticalSpacing; + + HDC hdc = CreateIC( "Display", 0, 0, 0); + UINT avcwCaption; + INT CaptionWidth; + MINIMIZEDMETRICS minim; + NONCLIENTMETRICS ncm; + minim.cbSize = sizeof( minim); + ncm.cbSize = sizeof( ncm); + SystemParametersInfo( SPI_GETMINIMIZEDMETRICS, 0, &minim, 0); + SystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0); + + /* CaptionWidth from the registry may have different value of iCaptionWidth + * from the non client metrics (observed on WinXP) */ + CaptionWidth = metricfromreg( + "Control Panel\\Desktop\\WindowMetrics","CaptionWidth", dpi); + get_text_metr_size( hdc, &ncm.lfMenuFont, &tmMenuFont, NULL); + get_text_metr_size( hdc, &ncm.lfCaptionFont, NULL, &avcwCaption); + /* FIXME: use icon metric */ + if( !SystemParametersInfoA( SPI_ICONVERTICALSPACING, 0, &IconVerticalSpacing, 0)) + IconVerticalSpacing = 0; + if( !SystemParametersInfoA( SPI_ICONHORIZONTALSPACING, 0, &IconSpacing, 0 )) + IconSpacing = 0; + /* reset error counters */ + gsm_error_ctr = 0; + + /* the tests: */ + + /* SM_CXSCREEN, can not test these two */ + /* SM_CYSCREEN */ + ok_gsm( SM_CXVSCROLL, ncm.iScrollWidth); + ok_gsm( SM_CYHSCROLL, ncm.iScrollWidth); + ok_gsm( SM_CYCAPTION, ncm.iCaptionHeight+1); + ok_gsm( SM_CXBORDER, 1); + ok_gsm( SM_CYBORDER, 1); + ok_gsm( SM_CXDLGFRAME, 3); + ok_gsm( SM_CYDLGFRAME, 3); + ok_gsm( SM_CYVTHUMB, ncm.iScrollHeight); + ok_gsm( SM_CXHTHUMB, ncm.iScrollHeight); + /* SM_CXICON */ + /* SM_CYICON */ + /* SM_CXCURSOR */ + /* SM_CYCURSOR */ + ok_gsm( SM_CYMENU, ncm.iMenuHeight + 1); + ok_gsm( SM_CXFULLSCREEN, + GetSystemMetrics( SM_CXMAXIMIZED) - 2 * GetSystemMetrics( SM_CXFRAME)); + ok_gsm( SM_CYFULLSCREEN, + GetSystemMetrics( SM_CYMAXIMIZED) - GetSystemMetrics( SM_CYMIN)); + /* SM_CYKANJIWINDOW */ + /* SM_MOUSEPRESENT */ + ok_gsm( SM_CYVSCROLL, ncm.iScrollHeight); + ok_gsm( SM_CXHSCROLL, ncm.iScrollHeight); + /* SM_DEBUG */ + /* SM_SWAPBUTTON */ + /* SM_RESERVED1 */ + /* SM_RESERVED2 */ + /* SM_RESERVED3 */ + /* SM_RESERVED4 */ + ok_gsm( SM_CXMIN, 3 * max( CaptionWidth, 8) + GetSystemMetrics( SM_CYSIZE) + + 4 + 4 * avcwCaption + 2 * GetSystemMetrics( SM_CXFRAME)); + ok_gsm( SM_CYMIN, GetSystemMetrics( SM_CYCAPTION) + + 2 * GetSystemMetrics( SM_CYFRAME)); + ok_gsm_2( SM_CXSIZE, + ncm.iCaptionWidth, /* classic/standard windows style */ + GetSystemMetrics( SM_CYCAPTION) - 1 /* WinXP style */ + ); + ok_gsm( SM_CYSIZE, ncm.iCaptionHeight); + ok_gsm( SM_CXFRAME, ncm.iBorderWidth + 3); + ok_gsm( SM_CYFRAME, ncm.iBorderWidth + 3); + ok_gsm( SM_CXMINTRACK, GetSystemMetrics( SM_CXMIN)); + ok_gsm( SM_CYMINTRACK, GetSystemMetrics( SM_CYMIN)); + /* SM_CXDOUBLECLK */ + /* SM_CYDOUBLECLK */ + if( IconSpacing) ok_gsm( SM_CXICONSPACING, IconSpacing); + if( IconVerticalSpacing) ok_gsm( SM_CYICONSPACING, IconVerticalSpacing); + /* SM_MENUDROPALIGNMENT */ + /* SM_PENWINDOWS */ + /* SM_DBCSENABLED */ + /* SM_CMOUSEBUTTONS */ + /* SM_SECURE */ + ok_gsm( SM_CXEDGE, 2); + ok_gsm( SM_CYEDGE, 2); + ok_gsm( SM_CXMINSPACING, GetSystemMetrics( SM_CXMINIMIZED) + minim.iHorzGap ); + ok_gsm( SM_CYMINSPACING, GetSystemMetrics( SM_CYMINIMIZED) + minim.iVertGap ); + /* SM_CXSMICON */ + /* SM_CYSMICON */ + ok_gsm( SM_CYSMCAPTION, ncm.iSmCaptionHeight + 1); + ok_gsm_3( SM_CXSMSIZE, + ncm.iSmCaptionWidth, /* classic/standard windows style */ + GetSystemMetrics( SM_CYSMCAPTION) - 1, /* WinXP style */ + smcxsmsize /* winXP seems to cache this value: setnonclientmetric + does not change it */ + ); + ok_gsm( SM_CYSMSIZE, GetSystemMetrics( SM_CYSMCAPTION) - 1); + ok_gsm( SM_CXMENUSIZE, ncm.iMenuWidth); + ok_gsm( SM_CYMENUSIZE, ncm.iMenuHeight); + /* SM_ARRANGE */ + ok_gsm( SM_CXMINIMIZED, minim.iWidth + 6); + ok_gsm( SM_CYMINIMIZED, GetSystemMetrics( SM_CYCAPTION) + 5); + ok_gsm( SM_CXMAXTRACK, GetSystemMetrics( SM_CXSCREEN) + + 4 + 2 * GetSystemMetrics( SM_CXFRAME)); + ok_gsm( SM_CYMAXTRACK, GetSystemMetrics( SM_CYSCREEN) + + 4 + 2 * GetSystemMetrics( SM_CYFRAME)); + /* the next two cannot really be tested as they depend on (application) + * toolbars */ + /* SM_CXMAXIMIZED */ + /* SM_CYMAXIMIZED */ + /* SM_NETWORK */ + /* */ + /* */ + /* */ + /* SM_CLEANBOOT */ + /* SM_CXDRAG */ + /* SM_CYDRAG */ + /* SM_SHOWSOUNDS */ + ok_gsm( SM_CXMENUCHECK, + ((tmMenuFont.tmHeight + tmMenuFont.tmExternalLeading+1)/2)*2-1); + ok_gsm( SM_CYMENUCHECK, + ((tmMenuFont.tmHeight + tmMenuFont.tmExternalLeading+1)/2)*2-1); + /* SM_SLOWMACHINE */ + /* SM_MIDEASTENABLED */ + /* SM_MOUSEWHEELPRESENT */ + /* SM_XVIRTUALSCREEN */ + /* SM_YVIRTUALSCREEN */ + /* SM_CXVIRTUALSCREEN */ + /* SM_CYVIRTUALSCREEN */ + /* SM_CMONITORS */ + /* SM_SAMEDISPLAYFORMAT */ + /* SM_IMMENABLED */ + /* SM_CXFOCUSBORDER */ + /* SM_CYFOCUSBORDER */ + /* SM_TABLETPC */ + /* SM_MEDIACENTER */ + /* SM_CMETRICS */ + /* end of tests */ + if( gsm_error_ctr ) { /* if any errors where found */ + trace( "BorderWidth %d CaptionWidth %d CaptionHeight %d IconSpacing %d IconVerticalSpacing %d\n", + ncm.iBorderWidth, ncm.iCaptionWidth, ncm.iCaptionHeight, IconSpacing, IconVerticalSpacing); + trace( "MenuHeight %d MenuWidth %d ScrollHeight %d ScrollWidth %d SmCaptionHeight %d SmCaptionWidth %d\n", + ncm.iMenuHeight, ncm.iMenuWidth, ncm.iScrollHeight, ncm.iScrollWidth, ncm.iSmCaptionHeight, ncm.iSmCaptionWidth); + trace( "Captionfontchar width %d MenuFont %ld,%ld CaptionWidth from registry: %d\n", + avcwCaption, tmMenuFont.tmHeight, tmMenuFont.tmExternalLeading, CaptionWidth); + } + ReleaseDC( 0, hdc); +} + START_TEST(sysparams) { int argc; @@ -1829,7 +2050,6 @@ START_TEST(sysparams) dpi = GetDeviceCaps( hdc, LOGPIXELSY); ReleaseDC( 0, hdc); - /* This test requires interactivity, if we don't have it, give up */ if (!SystemParametersInfoA( SPI_SETBEEP, TRUE, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ) && GetLastError()==ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION) return; @@ -1838,6 +2058,9 @@ START_TEST(sysparams) strict=(argc >= 3 && strcmp(argv[2],"strict")==0); trace("strict=%d\n",strict); + trace("testing GetSystemMetrics with your current desktop settings\n"); + test_GetSystemMetrics( ); + change_counter = 0; change_last_param = 0;