Sweden-Number/dlls/user32/sysparams.c

4963 lines
175 KiB
C

/*
* System parameters functions
*
* Copyright 1994 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <assert.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "windef.h"
#include "winbase.h"
#include "winnls.h"
#include "wingdi.h"
#include "winuser.h"
#include "winreg.h"
#include "wine/wingdi16.h"
#include "winerror.h"
#include "initguid.h"
#include "d3dkmdt.h"
#include "devguid.h"
#include "setupapi.h"
#include "controls.h"
#include "win.h"
#include "user_private.h"
#include "wine/asm.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(system);
/* System parameter indexes */
enum spi_index
{
SPI_SETWORKAREA_IDX,
SPI_INDEX_COUNT
};
/**
* Names of the registry subkeys of HKEY_CURRENT_USER key and value names
* for the system parameters.
*/
/* the various registry keys that are used to store parameters */
enum parameter_key
{
COLORS_KEY,
DESKTOP_KEY,
KEYBOARD_KEY,
MOUSE_KEY,
METRICS_KEY,
SOUND_KEY,
VERSION_KEY,
SHOWSOUNDS_KEY,
KEYBOARDPREF_KEY,
SCREENREADER_KEY,
AUDIODESC_KEY,
NB_PARAM_KEYS
};
static const WCHAR *parameter_key_names[NB_PARAM_KEYS] =
{
L"Control Panel\\Colors",
L"Control Panel\\Desktop",
L"Control Panel\\Keyboard",
L"Control Panel\\Mouse",
L"Control Panel\\Desktop\\WindowMetrics",
L"Control Panel\\Sound",
L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows",
L"Control Panel\\Accessibility\\ShowSounds",
L"Control Panel\\Accessibility\\Keyboard Preference",
L"Control Panel\\Accessibility\\Blind Access",
L"Control Panel\\Accessibility\\AudioDescription",
};
DEFINE_DEVPROPKEY(DEVPROPKEY_GPU_LUID, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6, 2);
DEFINE_DEVPROPKEY(DEVPROPKEY_MONITOR_GPU_LUID, 0xca085853, 0x16ce, 0x48aa, 0xb1, 0x14, 0xde, 0x9c, 0x72, 0x33, 0x42, 0x23, 1);
DEFINE_DEVPROPKEY(DEVPROPKEY_MONITOR_OUTPUT_ID, 0xca085853, 0x16ce, 0x48aa, 0xb1, 0x14, 0xde, 0x9c, 0x72, 0x33, 0x42, 0x23, 2);
/* Wine specific monitor properties */
DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_STATEFLAGS, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 2);
DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_RCMONITOR, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 3);
DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_RCWORK, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 4);
DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_ADAPTERNAME, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 5);
#define NULLDRV_DEFAULT_HMONITOR ((HMONITOR)(UINT_PTR)(0x10000 + 1))
/* Cached display device information */
struct display_device
{
struct list entry; /* Device list entry */
struct list children; /* Child device list entry. For adapters, this is monitor list. For monitors, this is unused. */
WCHAR device_name[32]; /* as DeviceName in DISPLAY_DEVICEW */
WCHAR device_string[128]; /* as DeviceString in DISPLAY_DEVICEW */
DWORD state_flags; /* as StateFlags in DISPLAY_DEVICEW */
WCHAR device_id[128]; /* as DeviceID in DISPLAY_DEVICEW when EDD_GET_DEVICE_INTERFACE_NAME is not set */
WCHAR interface_name[128]; /* as DeviceID in DISPLAY_DEVICEW when EDD_GET_DEVICE_INTERFACE_NAME is set */
WCHAR device_key[128]; /* as DeviceKey in DISPLAY_DEVICEW */
};
static struct list adapters = LIST_INIT(adapters);
static FILETIME last_query_display_time;
static CRITICAL_SECTION display_section;
static CRITICAL_SECTION_DEBUG display_critsect_debug =
{
0, 0, &display_section,
{ &display_critsect_debug.ProcessLocksList, &display_critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": display_section") }
};
static CRITICAL_SECTION display_section = { &display_critsect_debug, -1, 0, 0, 0, 0 };
static BOOL enum_display_device( WCHAR *device, DWORD index, struct display_device *info );
/* Cached monitor information */
static MONITORINFOEXW *monitors;
static UINT monitor_count;
static FILETIME last_query_monitors_time;
static CRITICAL_SECTION monitors_section;
static CRITICAL_SECTION_DEBUG monitors_critsect_debug =
{
0, 0, &monitors_section,
{ &monitors_critsect_debug.ProcessLocksList, &monitors_critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": monitors_section") }
};
static CRITICAL_SECTION monitors_section = { &monitors_critsect_debug, -1 , 0, 0, 0, 0 };
static HDC display_dc;
static CRITICAL_SECTION display_dc_section;
static CRITICAL_SECTION_DEBUG critsect_debug =
{
0, 0, &display_dc_section,
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": display_dc_section") }
};
static CRITICAL_SECTION display_dc_section = { &critsect_debug, -1 ,0, 0, 0, 0 };
/* Indicators whether system parameter value is loaded */
static char spi_loaded[SPI_INDEX_COUNT];
static BOOL notify_change = TRUE;
/* System parameters storage */
static RECT work_area;
static UINT system_dpi;
static DPI_AWARENESS dpi_awareness;
static DPI_AWARENESS default_awareness = DPI_AWARENESS_UNAWARE;
static HKEY volatile_base_key;
static HKEY video_key;
union sysparam_all_entry;
struct sysparam_entry
{
BOOL (*get)( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi );
BOOL (*set)( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags );
BOOL (*init)( union sysparam_all_entry *entry );
enum parameter_key base_key;
const WCHAR *regval;
enum parameter_key mirror_key;
const WCHAR *mirror;
BOOL loaded;
};
struct sysparam_uint_entry
{
struct sysparam_entry hdr;
UINT val;
};
struct sysparam_bool_entry
{
struct sysparam_entry hdr;
BOOL val;
};
struct sysparam_dword_entry
{
struct sysparam_entry hdr;
DWORD val;
};
struct sysparam_rgb_entry
{
struct sysparam_entry hdr;
COLORREF val;
HBRUSH brush;
HPEN pen;
};
struct sysparam_binary_entry
{
struct sysparam_entry hdr;
void *ptr;
size_t size;
};
struct sysparam_path_entry
{
struct sysparam_entry hdr;
WCHAR path[MAX_PATH];
};
struct sysparam_font_entry
{
struct sysparam_entry hdr;
UINT weight;
LOGFONTW val;
WCHAR fullname[LF_FACESIZE];
};
struct sysparam_pref_entry
{
struct sysparam_entry hdr;
struct sysparam_binary_entry *parent;
UINT offset;
UINT mask;
};
union sysparam_all_entry
{
struct sysparam_entry hdr;
struct sysparam_uint_entry uint;
struct sysparam_bool_entry bool;
struct sysparam_dword_entry dword;
struct sysparam_rgb_entry rgb;
struct sysparam_binary_entry bin;
struct sysparam_path_entry path;
struct sysparam_font_entry font;
struct sysparam_pref_entry pref;
};
static void SYSPARAMS_LogFont16To32W( const LOGFONT16 *font16, LPLOGFONTW font32 )
{
font32->lfHeight = font16->lfHeight;
font32->lfWidth = font16->lfWidth;
font32->lfEscapement = font16->lfEscapement;
font32->lfOrientation = font16->lfOrientation;
font32->lfWeight = font16->lfWeight;
font32->lfItalic = font16->lfItalic;
font32->lfUnderline = font16->lfUnderline;
font32->lfStrikeOut = font16->lfStrikeOut;
font32->lfCharSet = font16->lfCharSet;
font32->lfOutPrecision = font16->lfOutPrecision;
font32->lfClipPrecision = font16->lfClipPrecision;
font32->lfQuality = font16->lfQuality;
font32->lfPitchAndFamily = font16->lfPitchAndFamily;
MultiByteToWideChar( CP_ACP, 0, font16->lfFaceName, -1, font32->lfFaceName, LF_FACESIZE );
font32->lfFaceName[LF_FACESIZE-1] = 0;
}
static void SYSPARAMS_LogFont32WTo32A( const LOGFONTW* font32W, LPLOGFONTA font32A )
{
font32A->lfHeight = font32W->lfHeight;
font32A->lfWidth = font32W->lfWidth;
font32A->lfEscapement = font32W->lfEscapement;
font32A->lfOrientation = font32W->lfOrientation;
font32A->lfWeight = font32W->lfWeight;
font32A->lfItalic = font32W->lfItalic;
font32A->lfUnderline = font32W->lfUnderline;
font32A->lfStrikeOut = font32W->lfStrikeOut;
font32A->lfCharSet = font32W->lfCharSet;
font32A->lfOutPrecision = font32W->lfOutPrecision;
font32A->lfClipPrecision = font32W->lfClipPrecision;
font32A->lfQuality = font32W->lfQuality;
font32A->lfPitchAndFamily = font32W->lfPitchAndFamily;
WideCharToMultiByte( CP_ACP, 0, font32W->lfFaceName, -1, font32A->lfFaceName, LF_FACESIZE, NULL, NULL );
font32A->lfFaceName[LF_FACESIZE-1] = 0;
}
static void SYSPARAMS_LogFont32ATo32W( const LOGFONTA* font32A, LPLOGFONTW font32W )
{
font32W->lfHeight = font32A->lfHeight;
font32W->lfWidth = font32A->lfWidth;
font32W->lfEscapement = font32A->lfEscapement;
font32W->lfOrientation = font32A->lfOrientation;
font32W->lfWeight = font32A->lfWeight;
font32W->lfItalic = font32A->lfItalic;
font32W->lfUnderline = font32A->lfUnderline;
font32W->lfStrikeOut = font32A->lfStrikeOut;
font32W->lfCharSet = font32A->lfCharSet;
font32W->lfOutPrecision = font32A->lfOutPrecision;
font32W->lfClipPrecision = font32A->lfClipPrecision;
font32W->lfQuality = font32A->lfQuality;
font32W->lfPitchAndFamily = font32A->lfPitchAndFamily;
MultiByteToWideChar( CP_ACP, 0, font32A->lfFaceName, -1, font32W->lfFaceName, LF_FACESIZE );
font32W->lfFaceName[LF_FACESIZE-1] = 0;
}
static void SYSPARAMS_NonClientMetrics32WTo32A( const NONCLIENTMETRICSW* lpnm32W, LPNONCLIENTMETRICSA lpnm32A )
{
lpnm32A->iBorderWidth = lpnm32W->iBorderWidth;
lpnm32A->iScrollWidth = lpnm32W->iScrollWidth;
lpnm32A->iScrollHeight = lpnm32W->iScrollHeight;
lpnm32A->iCaptionWidth = lpnm32W->iCaptionWidth;
lpnm32A->iCaptionHeight = lpnm32W->iCaptionHeight;
SYSPARAMS_LogFont32WTo32A( &lpnm32W->lfCaptionFont, &lpnm32A->lfCaptionFont );
lpnm32A->iSmCaptionWidth = lpnm32W->iSmCaptionWidth;
lpnm32A->iSmCaptionHeight = lpnm32W->iSmCaptionHeight;
SYSPARAMS_LogFont32WTo32A( &lpnm32W->lfSmCaptionFont, &lpnm32A->lfSmCaptionFont );
lpnm32A->iMenuWidth = lpnm32W->iMenuWidth;
lpnm32A->iMenuHeight = lpnm32W->iMenuHeight;
SYSPARAMS_LogFont32WTo32A( &lpnm32W->lfMenuFont, &lpnm32A->lfMenuFont );
SYSPARAMS_LogFont32WTo32A( &lpnm32W->lfStatusFont, &lpnm32A->lfStatusFont );
SYSPARAMS_LogFont32WTo32A( &lpnm32W->lfMessageFont, &lpnm32A->lfMessageFont );
if (lpnm32A->cbSize > FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth))
{
if (lpnm32W->cbSize > FIELD_OFFSET(NONCLIENTMETRICSW, iPaddedBorderWidth))
lpnm32A->iPaddedBorderWidth = lpnm32W->iPaddedBorderWidth;
else
lpnm32A->iPaddedBorderWidth = 0;
}
}
static void SYSPARAMS_NonClientMetrics32ATo32W( const NONCLIENTMETRICSA* lpnm32A, LPNONCLIENTMETRICSW lpnm32W )
{
lpnm32W->iBorderWidth = lpnm32A->iBorderWidth;
lpnm32W->iScrollWidth = lpnm32A->iScrollWidth;
lpnm32W->iScrollHeight = lpnm32A->iScrollHeight;
lpnm32W->iCaptionWidth = lpnm32A->iCaptionWidth;
lpnm32W->iCaptionHeight = lpnm32A->iCaptionHeight;
SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfCaptionFont, &lpnm32W->lfCaptionFont );
lpnm32W->iSmCaptionWidth = lpnm32A->iSmCaptionWidth;
lpnm32W->iSmCaptionHeight = lpnm32A->iSmCaptionHeight;
SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfSmCaptionFont, &lpnm32W->lfSmCaptionFont );
lpnm32W->iMenuWidth = lpnm32A->iMenuWidth;
lpnm32W->iMenuHeight = lpnm32A->iMenuHeight;
SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfMenuFont, &lpnm32W->lfMenuFont );
SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfStatusFont, &lpnm32W->lfStatusFont );
SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfMessageFont, &lpnm32W->lfMessageFont );
if (lpnm32W->cbSize > FIELD_OFFSET(NONCLIENTMETRICSW, iPaddedBorderWidth))
{
if (lpnm32A->cbSize > FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth))
lpnm32W->iPaddedBorderWidth = lpnm32A->iPaddedBorderWidth;
else
lpnm32W->iPaddedBorderWidth = 0;
}
}
/* Helper functions to retrieve monitors info */
static BOOL CALLBACK get_virtual_screen_proc( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
{
RECT *virtual_rect = (RECT *)lp;
UnionRect( virtual_rect, virtual_rect, rect );
return TRUE;
}
RECT get_virtual_screen_rect(void)
{
RECT rect = {0};
EnumDisplayMonitors( 0, NULL, get_virtual_screen_proc, (LPARAM)&rect );
return rect;
}
static BOOL CALLBACK get_primary_monitor_proc( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
{
RECT *primary_rect = (RECT *)lp;
if (!rect->top && !rect->left && rect->right && rect->bottom)
{
*primary_rect = *rect;
return FALSE;
}
return TRUE;
}
RECT get_primary_monitor_rect(void)
{
RECT rect = {0};
EnumDisplayMonitors( 0, NULL, get_primary_monitor_proc, (LPARAM)&rect );
return rect;
}
static BOOL CALLBACK get_monitor_count_proc( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
{
INT *count = (INT *)lp;
++(*count);
return TRUE;
}
static INT get_monitor_count(void)
{
INT count = 0;
EnumDisplayMonitors( 0, NULL, get_monitor_count_proc, (LPARAM)&count );
return count;
}
static BOOL get_primary_adapter(WCHAR *name)
{
DISPLAY_DEVICEW dd;
DWORD i;
dd.cb = sizeof(dd);
for (i = 0; EnumDisplayDevicesW(NULL, i, &dd, 0); ++i)
{
if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
{
lstrcpyW(name, dd.DeviceName);
return TRUE;
}
}
return FALSE;
}
static BOOL is_valid_adapter_name(const WCHAR *name)
{
long int adapter_idx;
WCHAR *end;
if (wcsnicmp(name, L"\\\\.\\DISPLAY", lstrlenW(L"\\\\.\\DISPLAY")))
return FALSE;
adapter_idx = wcstol(name + lstrlenW(L"\\\\.\\DISPLAY"), &end, 10);
if (*end || adapter_idx < 1)
return FALSE;
return TRUE;
}
/* 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);
}
/***********************************************************************
* SYSPARAMS_NotifyChange
*
* Sends notification about system parameter update.
*/
static void SYSPARAMS_NotifyChange( UINT uiAction, UINT fWinIni )
{
static const WCHAR emptyW[1];
if (notify_change)
{
if (fWinIni & SPIF_UPDATEINIFILE)
{
if (fWinIni & (SPIF_SENDWININICHANGE | SPIF_SENDCHANGE))
SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE,
uiAction, (LPARAM) emptyW,
SMTO_ABORTIFHUNG, 2000, NULL );
}
else
{
/* FIXME notify other wine processes with internal message */
}
}
}
/* retrieve the cached base keys for a given entry */
static BOOL get_base_keys( enum parameter_key index, HKEY *base_key, HKEY *volatile_key )
{
static HKEY base_keys[NB_PARAM_KEYS];
static HKEY volatile_keys[NB_PARAM_KEYS];
HKEY key;
if (!base_keys[index] && base_key)
{
if (RegCreateKeyW( HKEY_CURRENT_USER, parameter_key_names[index], &key )) return FALSE;
if (InterlockedCompareExchangePointer( (void **)&base_keys[index], key, 0 ))
RegCloseKey( key );
}
if (!volatile_keys[index] && volatile_key)
{
if (RegCreateKeyExW( volatile_base_key, parameter_key_names[index],
0, 0, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &key, 0 )) return FALSE;
if (InterlockedCompareExchangePointer( (void **)&volatile_keys[index], key, 0 ))
RegCloseKey( key );
}
if (base_key) *base_key = base_keys[index];
if (volatile_key) *volatile_key = volatile_keys[index];
return TRUE;
}
/* load a value to a registry entry */
static DWORD load_entry( struct sysparam_entry *entry, void *data, DWORD size )
{
DWORD type, count;
HKEY base_key, volatile_key;
if (!get_base_keys( entry->base_key, &base_key, &volatile_key )) return FALSE;
count = size;
if (RegQueryValueExW( volatile_key, entry->regval, NULL, &type, data, &count ))
{
count = size;
if (RegQueryValueExW( base_key, entry->regval, NULL, &type, data, &count )) count = 0;
}
/* make sure strings are null-terminated */
if (size && count == size && type == REG_SZ) ((WCHAR *)data)[count / sizeof(WCHAR) - 1] = 0;
entry->loaded = TRUE;
return count;
}
/* save a value to a registry entry */
static BOOL save_entry( const struct sysparam_entry *entry, const void *data, DWORD size,
DWORD type, UINT flags )
{
HKEY base_key, volatile_key;
if (flags & SPIF_UPDATEINIFILE)
{
if (!get_base_keys( entry->base_key, &base_key, &volatile_key )) return FALSE;
if (RegSetValueExW( base_key, entry->regval, 0, type, data, size )) return FALSE;
RegDeleteValueW( volatile_key, entry->regval );
if (entry->mirror && get_base_keys( entry->mirror_key, &base_key, NULL ))
RegSetValueExW( base_key, entry->mirror, 0, type, data, size );
}
else
{
if (!get_base_keys( entry->base_key, NULL, &volatile_key )) return FALSE;
if (RegSetValueExW( volatile_key, entry->regval, 0, type, data, size )) return FALSE;
}
return TRUE;
}
/* save a string value to a registry entry */
static BOOL save_entry_string( const struct sysparam_entry *entry, const WCHAR *str, UINT flags )
{
return save_entry( entry, str, (lstrlenW(str) + 1) * sizeof(WCHAR), REG_SZ, flags );
}
/* initialize an entry in the registry if missing */
static BOOL init_entry( struct sysparam_entry *entry, const void *data, DWORD size, DWORD type )
{
HKEY base_key;
if (!get_base_keys( entry->base_key, &base_key, NULL )) return FALSE;
if (!RegQueryValueExW( base_key, entry->regval, NULL, NULL, NULL, NULL )) return TRUE;
if (RegSetValueExW( base_key, entry->regval, 0, type, data, size )) return FALSE;
if (entry->mirror && get_base_keys( entry->mirror_key, &base_key, NULL ))
RegSetValueExW( base_key, entry->mirror, 0, type, data, size );
entry->loaded = TRUE;
return TRUE;
}
/* initialize a string value in the registry if missing */
static BOOL init_entry_string( struct sysparam_entry *entry, const WCHAR *str )
{
return init_entry( entry, str, (lstrlenW(str) + 1) * sizeof(WCHAR), REG_SZ );
}
HDC get_display_dc(void)
{
EnterCriticalSection( &display_dc_section );
if (!display_dc)
{
HDC dc;
LeaveCriticalSection( &display_dc_section );
dc = CreateDCW( L"DISPLAY", NULL, NULL, NULL );
EnterCriticalSection( &display_dc_section );
if (display_dc)
DeleteDC(dc);
else
display_dc = dc;
}
return display_dc;
}
void release_display_dc( HDC hdc )
{
LeaveCriticalSection( &display_dc_section );
}
static HANDLE get_display_device_init_mutex( void )
{
HANDLE mutex = CreateMutexW( NULL, FALSE, L"display_device_init" );
WaitForSingleObject( mutex, INFINITE );
return mutex;
}
static void release_display_device_init_mutex( HANDLE mutex )
{
ReleaseMutex( mutex );
CloseHandle( mutex );
}
/* Wait until graphics driver is loaded by explorer */
void wait_graphics_driver_ready(void)
{
static BOOL ready = FALSE;
if (!ready)
{
SendMessageW( GetDesktopWindow(), WM_NULL, 0, 0 );
ready = TRUE;
}
}
/* map value from system dpi to standard 96 dpi for storing in the registry */
static int map_from_system_dpi( int val )
{
return MulDiv( val, USER_DEFAULT_SCREEN_DPI, GetDpiForSystem() );
}
/* map value from 96 dpi to system or custom dpi */
static int map_to_dpi( int val, UINT dpi )
{
if (!dpi) dpi = GetDpiForSystem();
return MulDiv( val, dpi, USER_DEFAULT_SCREEN_DPI );
}
static INT CALLBACK real_fontname_proc(const LOGFONTW *lf, const TEXTMETRICW *ntm, DWORD type, LPARAM lparam)
{
const ENUMLOGFONTW *elf = (const ENUMLOGFONTW *)lf;
WCHAR *fullname = (WCHAR *)lparam;
lstrcpynW( fullname, elf->elfFullName, LF_FACESIZE );
return 0;
}
static void get_real_fontname( LOGFONTW *lf, WCHAR fullname[LF_FACESIZE] )
{
HDC hdc = get_display_dc();
lstrcpyW( fullname, lf->lfFaceName );
EnumFontFamiliesExW( hdc, lf, real_fontname_proc, (LPARAM)fullname, 0 );
release_display_dc( hdc );
}
/* adjust some of the raw values found in the registry */
static void normalize_nonclientmetrics( NONCLIENTMETRICSW *pncm)
{
TEXTMETRICW tm;
HDC hdc = get_display_dc();
if( pncm->iBorderWidth < 1) pncm->iBorderWidth = 1;
if( pncm->iCaptionWidth < 8) pncm->iCaptionWidth = 8;
if( pncm->iScrollWidth < 8) pncm->iScrollWidth = 8;
if( pncm->iScrollHeight < 8) pncm->iScrollHeight = 8;
/* adjust some heights to the corresponding font */
get_text_metr_size( hdc, &pncm->lfMenuFont, &tm, NULL);
pncm->iMenuHeight = max( pncm->iMenuHeight, 2 + tm.tmHeight + tm.tmExternalLeading );
get_text_metr_size( hdc, &pncm->lfCaptionFont, &tm, NULL);
pncm->iCaptionHeight = max( pncm->iCaptionHeight, 2 + tm.tmHeight);
get_text_metr_size( hdc, &pncm->lfSmCaptionFont, &tm, NULL);
pncm->iSmCaptionHeight = max( pncm->iSmCaptionHeight, 2 + tm.tmHeight);
release_display_dc( hdc );
}
static BOOL CALLBACK enum_monitors( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
{
MONITORINFO mi;
mi.cbSize = sizeof(mi);
if (GetMonitorInfoW( monitor, &mi ) && (mi.dwFlags & MONITORINFOF_PRIMARY))
{
LPRECT work = (LPRECT)lp;
*work = mi.rcWork;
return FALSE;
}
return TRUE;
}
/* load a uint parameter from the registry */
static BOOL get_uint_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
{
if (!ptr_param) return FALSE;
if (!entry->hdr.loaded)
{
WCHAR buf[32];
if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->uint.val = wcstol( buf, NULL, 10 );
}
*(UINT *)ptr_param = entry->uint.val;
return TRUE;
}
/* set a uint parameter in the registry */
static BOOL set_uint_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
{
WCHAR buf[32];
wsprintfW( buf, L"%u", int_param );
if (!save_entry_string( &entry->hdr, buf, flags )) return FALSE;
entry->uint.val = int_param;
entry->hdr.loaded = TRUE;
return TRUE;
}
/* initialize a uint parameter */
static BOOL init_uint_entry( union sysparam_all_entry *entry )
{
WCHAR buf[32];
wsprintfW( buf, L"%u", entry->uint.val );
return init_entry_string( &entry->hdr, buf );
}
/* set an int parameter in the registry */
static BOOL set_int_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
{
WCHAR buf[32];
wsprintfW( buf, L"%d", int_param );
if (!save_entry_string( &entry->hdr, buf, flags )) return FALSE;
entry->uint.val = int_param;
entry->hdr.loaded = TRUE;
return TRUE;
}
/* initialize an int parameter */
static BOOL init_int_entry( union sysparam_all_entry *entry )
{
WCHAR buf[32];
wsprintfW( buf, L"%d", entry->uint.val );
return init_entry_string( &entry->hdr, buf );
}
/* load a twips parameter from the registry */
static BOOL get_twips_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
{
int val;
if (!ptr_param) return FALSE;
if (!entry->hdr.loaded)
{
WCHAR buf[32];
if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->uint.val = wcstol( buf, NULL, 10 );
}
/* Dimensions are quoted as being "twips" values if negative and pixels if positive.
* One inch is 1440 twips.
* See for example
* Technical Reference to the Windows 2000 Registry ->
* HKEY_CURRENT_USER -> Control Panel -> Desktop -> WindowMetrics
*/
val = entry->uint.val;
if (val < 0)
val = MulDiv( -val, dpi, 1440 );
else
val = map_to_dpi( val, dpi );
*(int *)ptr_param = val;
return TRUE;
}
/* set a twips parameter in the registry */
static BOOL set_twips_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
{
int val = int_param;
if (val > 0) val = map_from_system_dpi( val );
return set_int_entry( entry, val, ptr_param, flags );
}
/* load a bool parameter from the registry */
static BOOL get_bool_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
{
if (!ptr_param) return FALSE;
if (!entry->hdr.loaded)
{
WCHAR buf[32];
if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->bool.val = wcstol( buf, NULL, 10 ) != 0;
}
*(UINT *)ptr_param = entry->bool.val;
return TRUE;
}
/* set a bool parameter in the registry */
static BOOL set_bool_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
{
WCHAR buf[32];
wsprintfW( buf, L"%u", int_param != 0 );
if (!save_entry_string( &entry->hdr, buf, flags )) return FALSE;
entry->bool.val = int_param != 0;
entry->hdr.loaded = TRUE;
return TRUE;
}
/* initialize a bool parameter */
static BOOL init_bool_entry( union sysparam_all_entry *entry )
{
WCHAR buf[32];
wsprintfW( buf, L"%u", entry->bool.val != 0 );
return init_entry_string( &entry->hdr, buf );
}
/* load a bool parameter using Yes/No strings from the registry */
static BOOL get_yesno_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
{
if (!ptr_param) return FALSE;
if (!entry->hdr.loaded)
{
WCHAR buf[32];
if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->bool.val = !lstrcmpiW( L"Yes", buf );
}
*(UINT *)ptr_param = entry->bool.val;
return TRUE;
}
/* set a bool parameter using Yes/No strings from the registry */
static BOOL set_yesno_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
{
const WCHAR *str = int_param ? L"Yes" : L"No";
if (!save_entry_string( &entry->hdr, str, flags )) return FALSE;
entry->bool.val = int_param != 0;
entry->hdr.loaded = TRUE;
return TRUE;
}
/* initialize a bool parameter using Yes/No strings */
static BOOL init_yesno_entry( union sysparam_all_entry *entry )
{
return init_entry_string( &entry->hdr, entry->bool.val ? L"Yes" : L"No" );
}
/* load a dword (binary) parameter from the registry */
static BOOL get_dword_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
{
if (!ptr_param) return FALSE;
if (!entry->hdr.loaded)
{
DWORD val;
if (load_entry( &entry->hdr, &val, sizeof(val) ) == sizeof(DWORD)) entry->dword.val = val;
}
*(DWORD *)ptr_param = entry->dword.val;
return TRUE;
}
/* set a dword (binary) parameter in the registry */
static BOOL set_dword_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
{
DWORD val = PtrToUlong( ptr_param );
if (!save_entry( &entry->hdr, &val, sizeof(val), REG_DWORD, flags )) return FALSE;
entry->dword.val = val;
entry->hdr.loaded = TRUE;
return TRUE;
}
/* initialize a dword parameter */
static BOOL init_dword_entry( union sysparam_all_entry *entry )
{
return init_entry( &entry->hdr, &entry->dword.val, sizeof(entry->dword.val), REG_DWORD );
}
/* load an RGB parameter from the registry */
static BOOL get_rgb_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
{
if (!ptr_param) return FALSE;
if (!entry->hdr.loaded)
{
WCHAR buf[32];
if (load_entry( &entry->hdr, buf, sizeof(buf) ))
{
DWORD r, g, b;
WCHAR *end, *str = buf;
r = wcstoul( str, &end, 10 );
if (end == str || !*end) goto done;
str = end + 1;
g = wcstoul( str, &end, 10 );
if (end == str || !*end) goto done;
str = end + 1;
b = wcstoul( str, &end, 10 );
if (end == str) goto done;
if (r > 255 || g > 255 || b > 255) goto done;
entry->rgb.val = RGB( r, g, b );
}
}
done:
*(COLORREF *)ptr_param = entry->rgb.val;
return TRUE;
}
/* set an RGB parameter in the registry */
static BOOL set_rgb_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
{
WCHAR buf[32];
HBRUSH brush;
HPEN pen;
wsprintfW( buf, L"%u %u %u", GetRValue(int_param), GetGValue(int_param), GetBValue(int_param) );
if (!save_entry_string( &entry->hdr, buf, flags )) return FALSE;
entry->rgb.val = int_param;
entry->hdr.loaded = TRUE;
if ((brush = InterlockedExchangePointer( (void **)&entry->rgb.brush, 0 )))
{
__wine_make_gdi_object_system( brush, FALSE );
DeleteObject( brush );
}
if ((pen = InterlockedExchangePointer( (void **)&entry->rgb.pen, 0 )))
{
__wine_make_gdi_object_system( pen, FALSE );
DeleteObject( pen );
}
return TRUE;
}
/* initialize an RGB parameter */
static BOOL init_rgb_entry( union sysparam_all_entry *entry )
{
WCHAR buf[32];
wsprintfW( buf, L"%u %u %u", GetRValue(entry->rgb.val), GetGValue(entry->rgb.val), GetBValue(entry->rgb.val) );
return init_entry_string( &entry->hdr, buf );
}
/* load a font (binary) parameter from the registry */
static BOOL get_font_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
{
LOGFONTW font;
if (!ptr_param) return FALSE;
if (!entry->hdr.loaded)
{
switch (load_entry( &entry->hdr, &font, sizeof(font) ))
{
case sizeof(font):
if (font.lfHeight > 0) /* positive height value means points ( inch/72 ) */
font.lfHeight = -MulDiv( font.lfHeight, USER_DEFAULT_SCREEN_DPI, 72 );
entry->font.val = font;
break;
case sizeof(LOGFONT16): /* win9x-winME format */
SYSPARAMS_LogFont16To32W( (LOGFONT16 *)&font, &entry->font.val );
if (entry->font.val.lfHeight > 0)
entry->font.val.lfHeight = -MulDiv( entry->font.val.lfHeight, USER_DEFAULT_SCREEN_DPI, 72 );
break;
default:
WARN( "Unknown format in key %s value %s\n",
debugstr_w( parameter_key_names[entry->hdr.base_key] ),
debugstr_w( entry->hdr.regval ));
/* fall through */
case 0: /* use the default GUI font */
GetObjectW( GetStockObject( DEFAULT_GUI_FONT ), sizeof(font), &font );
font.lfHeight = map_from_system_dpi( font.lfHeight );
font.lfWeight = entry->font.weight;
entry->font.val = font;
break;
}
get_real_fontname( &entry->font.val, entry->font.fullname );
entry->hdr.loaded = TRUE;
}
font = entry->font.val;
font.lfHeight = map_to_dpi( font.lfHeight, dpi );
lstrcpyW( font.lfFaceName, entry->font.fullname );
*(LOGFONTW *)ptr_param = font;
return TRUE;
}
/* set a font (binary) parameter in the registry */
static BOOL set_font_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
{
LOGFONTW font;
WCHAR *ptr;
memcpy( &font, ptr_param, sizeof(font) );
/* zero pad the end of lfFaceName so we don't save uninitialised data */
ptr = wmemchr( font.lfFaceName, 0, LF_FACESIZE );
if (ptr) memset( ptr, 0, (font.lfFaceName + LF_FACESIZE - ptr) * sizeof(WCHAR) );
if (font.lfHeight < 0) font.lfHeight = map_from_system_dpi( font.lfHeight );
if (!save_entry( &entry->hdr, &font, sizeof(font), REG_BINARY, flags )) return FALSE;
entry->font.val = font;
get_real_fontname( &entry->font.val, entry->font.fullname );
entry->hdr.loaded = TRUE;
return TRUE;
}
/* initialize a font (binary) parameter */
static BOOL init_font_entry( union sysparam_all_entry *entry )
{
GetObjectW( GetStockObject( DEFAULT_GUI_FONT ), sizeof(entry->font.val), &entry->font.val );
entry->font.val.lfHeight = map_from_system_dpi( entry->font.val.lfHeight );
entry->font.val.lfWeight = entry->font.weight;
get_real_fontname( &entry->font.val, entry->font.fullname );
return init_entry( &entry->hdr, &entry->font.val, sizeof(entry->font.val), REG_BINARY );
}
/* get a path parameter in the registry */
static BOOL get_path_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
{
if (!ptr_param) return FALSE;
if (!entry->hdr.loaded)
{
WCHAR buffer[MAX_PATH];
if (load_entry( &entry->hdr, buffer, sizeof(buffer) ))
lstrcpynW( entry->path.path, buffer, MAX_PATH );
}
lstrcpynW( ptr_param, entry->path.path, int_param );
return TRUE;
}
/* set a path parameter in the registry */
static BOOL set_path_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
{
WCHAR buffer[MAX_PATH];
BOOL ret;
lstrcpynW( buffer, ptr_param, MAX_PATH );
ret = save_entry_string( &entry->hdr, buffer, flags );
if (ret)
{
lstrcpyW( entry->path.path, buffer );
entry->hdr.loaded = TRUE;
}
return ret;
}
/* initialize a path parameter */
static BOOL init_path_entry( union sysparam_all_entry *entry )
{
return init_entry_string( &entry->hdr, entry->path.path );
}
/* get a binary parameter in the registry */
static BOOL get_binary_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
{
if (!ptr_param) return FALSE;
if (!entry->hdr.loaded)
{
void *buffer = HeapAlloc( GetProcessHeap(), 0, entry->bin.size );
DWORD len = load_entry( &entry->hdr, buffer, entry->bin.size );
if (len)
{
memcpy( entry->bin.ptr, buffer, entry->bin.size );
memset( (char *)entry->bin.ptr + len, 0, entry->bin.size - len );
}
HeapFree( GetProcessHeap(), 0, buffer );
}
memcpy( ptr_param, entry->bin.ptr, min( int_param, entry->bin.size ) );
return TRUE;
}
/* set a binary parameter in the registry */
static BOOL set_binary_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
{
BOOL ret;
void *buffer = HeapAlloc( GetProcessHeap(), 0, entry->bin.size );
memcpy( buffer, entry->bin.ptr, entry->bin.size );
memcpy( buffer, ptr_param, min( int_param, entry->bin.size ));
ret = save_entry( &entry->hdr, buffer, entry->bin.size, REG_BINARY, flags );
if (ret)
{
memcpy( entry->bin.ptr, buffer, entry->bin.size );
entry->hdr.loaded = TRUE;
}
HeapFree( GetProcessHeap(), 0, buffer );
return ret;
}
/* initialize a binary parameter */
static BOOL init_binary_entry( union sysparam_all_entry *entry )
{
return init_entry( &entry->hdr, entry->bin.ptr, entry->bin.size, REG_BINARY );
}
/* get a user pref parameter in the registry */
static BOOL get_userpref_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
{
union sysparam_all_entry *parent_entry = (union sysparam_all_entry *)entry->pref.parent;
BYTE prefs[8];
if (!ptr_param) return FALSE;
if (!parent_entry->hdr.get( parent_entry, sizeof(prefs), prefs, dpi )) return FALSE;
*(BOOL *)ptr_param = (prefs[entry->pref.offset] & entry->pref.mask) != 0;
return TRUE;
}
/* set a user pref parameter in the registry */
static BOOL set_userpref_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
{
union sysparam_all_entry *parent_entry = (union sysparam_all_entry *)entry->pref.parent;
BYTE prefs[8];
parent_entry->hdr.loaded = FALSE; /* force loading it again */
if (!parent_entry->hdr.get( parent_entry, sizeof(prefs), prefs, GetDpiForSystem() )) return FALSE;
if (PtrToUlong( ptr_param )) prefs[entry->pref.offset] |= entry->pref.mask;
else prefs[entry->pref.offset] &= ~entry->pref.mask;
return parent_entry->hdr.set( parent_entry, sizeof(prefs), prefs, flags );
}
static BOOL get_entry_dpi( void *ptr, UINT int_param, void *ptr_param, UINT dpi )
{
union sysparam_all_entry *entry = ptr;
return entry->hdr.get( entry, int_param, ptr_param, dpi );
}
static BOOL get_entry( void *ptr, UINT int_param, void *ptr_param )
{
return get_entry_dpi( ptr, int_param, ptr_param, GetDpiForSystem() );
}
static BOOL set_entry( void *ptr, UINT int_param, void *ptr_param, UINT flags )
{
union sysparam_all_entry *entry = ptr;
return entry->hdr.set( entry, int_param, ptr_param, flags );
}
#define UINT_ENTRY(name,val,base,reg) \
struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_uint_entry, init_uint_entry, \
base, reg }, (val) }
#define UINT_ENTRY_MIRROR(name,val,base,reg,mirror_base) \
struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_uint_entry, init_uint_entry, \
base, reg, mirror_base, reg }, (val) }
#define INT_ENTRY(name,val,base,reg) \
struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_int_entry, init_int_entry, \
base, reg }, (val) }
#define BOOL_ENTRY(name,val,base,reg) \
struct sysparam_bool_entry entry_##name = { { get_bool_entry, set_bool_entry, init_bool_entry, \
base, reg }, (val) }
#define BOOL_ENTRY_MIRROR(name,val,base,reg,mirror_base) \
struct sysparam_bool_entry entry_##name = { { get_bool_entry, set_bool_entry, init_bool_entry, \
base, reg, mirror_base, reg }, (val) }
#define YESNO_ENTRY(name,val,base,reg) \
struct sysparam_bool_entry entry_##name = { { get_yesno_entry, set_yesno_entry, init_yesno_entry, \
base, reg }, (val) }
#define TWIPS_ENTRY(name,val,base,reg) \
struct sysparam_uint_entry entry_##name = { { get_twips_entry, set_twips_entry, init_int_entry, \
base, reg }, (val) }
#define DWORD_ENTRY(name,val,base,reg) \
struct sysparam_dword_entry entry_##name = { { get_dword_entry, set_dword_entry, init_dword_entry, \
base, reg }, (val) }
#define BINARY_ENTRY(name,data,base,reg) \
struct sysparam_binary_entry entry_##name = { { get_binary_entry, set_binary_entry, init_binary_entry, \
base, reg }, data, sizeof(data) }
#define PATH_ENTRY(name,base,reg) \
struct sysparam_path_entry entry_##name = { { get_path_entry, set_path_entry, init_path_entry, \
base, reg } }
#define FONT_ENTRY(name,weight,base,reg) \
struct sysparam_font_entry entry_##name = { { get_font_entry, set_font_entry, init_font_entry, \
base, reg }, (weight) }
#define USERPREF_ENTRY(name,offset,mask) \
struct sysparam_pref_entry entry_##name = { { get_userpref_entry, set_userpref_entry }, \
&entry_USERPREFERENCESMASK, (offset), (mask) }
static UINT_ENTRY( DRAGWIDTH, 4, DESKTOP_KEY, L"DragWidth" );
static UINT_ENTRY( DRAGHEIGHT, 4, DESKTOP_KEY, L"DragHeight" );
static UINT_ENTRY( DOUBLECLICKTIME, 500, MOUSE_KEY, L"DoubleClickSpeed" );
static UINT_ENTRY( FONTSMOOTHING, 2, DESKTOP_KEY, L"FontSmoothing" );
static UINT_ENTRY( GRIDGRANULARITY, 0, DESKTOP_KEY, L"GridGranularity" );
static UINT_ENTRY( KEYBOARDDELAY, 1, KEYBOARD_KEY, L"KeyboardDelay" );
static UINT_ENTRY( KEYBOARDSPEED, 31, KEYBOARD_KEY, L"KeyboardSpeed" );
static UINT_ENTRY( MENUSHOWDELAY, 400, DESKTOP_KEY, L"MenuShowDelay" );
static UINT_ENTRY( MINARRANGE, ARW_HIDE, METRICS_KEY, L"MinArrange" );
static UINT_ENTRY( MINHORZGAP, 0, METRICS_KEY, L"MinHorzGap" );
static UINT_ENTRY( MINVERTGAP, 0, METRICS_KEY, L"MinVertGap" );
static UINT_ENTRY( MINWIDTH, 154, METRICS_KEY, L"MinWidth" );
static UINT_ENTRY( MOUSEHOVERHEIGHT, 4, MOUSE_KEY, L"MouseHoverHeight" );
static UINT_ENTRY( MOUSEHOVERTIME, 400, MOUSE_KEY, L"MouseHoverTime" );
static UINT_ENTRY( MOUSEHOVERWIDTH, 4, MOUSE_KEY, L"MouseHoverWidth" );
static UINT_ENTRY( MOUSESPEED, 10, MOUSE_KEY, L"MouseSensitivity" );
static UINT_ENTRY( MOUSETRAILS, 0, MOUSE_KEY, L"MouseTrails" );
static UINT_ENTRY( SCREENSAVETIMEOUT, 300, DESKTOP_KEY, L"ScreenSaveTimeOut" );
static UINT_ENTRY( WHEELSCROLLCHARS, 3, DESKTOP_KEY, L"WheelScrollChars" );
static UINT_ENTRY( WHEELSCROLLLINES, 3, DESKTOP_KEY, L"WheelScrollLines" );
static UINT_ENTRY_MIRROR( DOUBLECLKHEIGHT, 4, MOUSE_KEY, L"DoubleClickHeight", DESKTOP_KEY );
static UINT_ENTRY_MIRROR( DOUBLECLKWIDTH, 4, MOUSE_KEY, L"DoubleClickWidth", DESKTOP_KEY );
static UINT_ENTRY_MIRROR( MENUDROPALIGNMENT, 0, DESKTOP_KEY, L"MenuDropAlignment", VERSION_KEY );
static INT_ENTRY( MOUSETHRESHOLD1, 6, MOUSE_KEY, L"MouseThreshold1" );
static INT_ENTRY( MOUSETHRESHOLD2, 10, MOUSE_KEY, L"MouseThreshold2" );
static INT_ENTRY( MOUSEACCELERATION, 1, MOUSE_KEY, L"MouseSpeed" );
static BOOL_ENTRY( BLOCKSENDINPUTRESETS, FALSE, DESKTOP_KEY, L"BlockSendInputResets" );
static BOOL_ENTRY( DRAGFULLWINDOWS, FALSE, DESKTOP_KEY, L"DragFullWindows" );
static BOOL_ENTRY( KEYBOARDPREF, TRUE, KEYBOARDPREF_KEY, L"On" );
static BOOL_ENTRY( LOWPOWERACTIVE, FALSE, DESKTOP_KEY, L"LowPowerActive" );
static BOOL_ENTRY( MOUSEBUTTONSWAP, FALSE, MOUSE_KEY, L"SwapMouseButtons" );
static BOOL_ENTRY( POWEROFFACTIVE, FALSE, DESKTOP_KEY, L"PowerOffActive" );
static BOOL_ENTRY( SCREENREADER, FALSE, SCREENREADER_KEY, L"On" );
static BOOL_ENTRY( SCREENSAVEACTIVE, TRUE, DESKTOP_KEY, L"ScreenSaveActive" );
static BOOL_ENTRY( SCREENSAVERRUNNING, FALSE, DESKTOP_KEY, L"WINE_ScreenSaverRunning" ); /* FIXME - real value */
static BOOL_ENTRY( SHOWSOUNDS, FALSE, SHOWSOUNDS_KEY, L"On" );
static BOOL_ENTRY( SNAPTODEFBUTTON, FALSE, MOUSE_KEY, L"SnapToDefaultButton" );
static BOOL_ENTRY_MIRROR( ICONTITLEWRAP, TRUE, DESKTOP_KEY, L"IconTitleWrap", METRICS_KEY );
static BOOL_ENTRY( AUDIODESC_ON, FALSE, AUDIODESC_KEY, L"On" );
static YESNO_ENTRY( BEEP, TRUE, SOUND_KEY, L"Beep" );
static TWIPS_ENTRY( BORDER, -15, METRICS_KEY, L"BorderWidth" );
static TWIPS_ENTRY( CAPTIONHEIGHT, -270, METRICS_KEY, L"CaptionHeight" );
static TWIPS_ENTRY( CAPTIONWIDTH, -270, METRICS_KEY, L"CaptionWidth" );
static TWIPS_ENTRY( ICONHORIZONTALSPACING, -1125, METRICS_KEY, L"IconSpacing" );
static TWIPS_ENTRY( ICONVERTICALSPACING, -1125, METRICS_KEY, L"IconVerticalSpacing" );
static TWIPS_ENTRY( MENUHEIGHT, -270, METRICS_KEY, L"MenuHeight" );
static TWIPS_ENTRY( MENUWIDTH, -270, METRICS_KEY, L"MenuWidth" );
static TWIPS_ENTRY( PADDEDBORDERWIDTH, 0, METRICS_KEY, L"PaddedBorderWidth" );
static TWIPS_ENTRY( SCROLLHEIGHT, -240, METRICS_KEY, L"ScrollHeight" );
static TWIPS_ENTRY( SCROLLWIDTH, -240, METRICS_KEY, L"ScrollWidth" );
static TWIPS_ENTRY( SMCAPTIONHEIGHT, -225, METRICS_KEY, L"SmCaptionHeight" );
static TWIPS_ENTRY( SMCAPTIONWIDTH, -225, METRICS_KEY, L"SmCaptionWidth" );
static DWORD_ENTRY( ACTIVEWINDOWTRACKING, 0, MOUSE_KEY, L"ActiveWindowTracking" );
static DWORD_ENTRY( ACTIVEWNDTRKTIMEOUT, 0, DESKTOP_KEY, L"ActiveWndTrackTimeout" );
static DWORD_ENTRY( CARETWIDTH, 1, DESKTOP_KEY, L"CaretWidth" );
static DWORD_ENTRY( DPISCALINGVER, 0, DESKTOP_KEY, L"DpiScalingVer" );
static DWORD_ENTRY( FOCUSBORDERHEIGHT, 1, DESKTOP_KEY, L"FocusBorderHeight" );
static DWORD_ENTRY( FOCUSBORDERWIDTH, 1, DESKTOP_KEY, L"FocusBorderWidth" );
static DWORD_ENTRY( FONTSMOOTHINGCONTRAST, 0, DESKTOP_KEY, L"FontSmoothingGamma" );
static DWORD_ENTRY( FONTSMOOTHINGORIENTATION, FE_FONTSMOOTHINGORIENTATIONRGB, DESKTOP_KEY, L"FontSmoothingOrientation" );
static DWORD_ENTRY( FONTSMOOTHINGTYPE, FE_FONTSMOOTHINGSTANDARD, DESKTOP_KEY, L"FontSmoothingType" );
static DWORD_ENTRY( FOREGROUNDFLASHCOUNT, 3, DESKTOP_KEY, L"ForegroundFlashCount" );
static DWORD_ENTRY( FOREGROUNDLOCKTIMEOUT, 0, DESKTOP_KEY, L"ForegroundLockTimeout" );
static DWORD_ENTRY( LOGPIXELS, 0, DESKTOP_KEY, L"LogPixels" );
static DWORD_ENTRY( MOUSECLICKLOCKTIME, 1200, DESKTOP_KEY, L"ClickLockTime" );
static DWORD_ENTRY( AUDIODESC_LOCALE, 0, AUDIODESC_KEY, L"Locale" );
static PATH_ENTRY( DESKPATTERN, DESKTOP_KEY, L"Pattern" );
static PATH_ENTRY( DESKWALLPAPER, DESKTOP_KEY, L"Wallpaper" );
static BYTE user_prefs[8] = { 0x30, 0x00, 0x00, 0x80, 0x12, 0x00, 0x00, 0x00 };
static BINARY_ENTRY( USERPREFERENCESMASK, user_prefs, DESKTOP_KEY, L"UserPreferencesMask" );
static FONT_ENTRY( CAPTIONLOGFONT, FW_BOLD, METRICS_KEY, L"CaptionFont" );
static FONT_ENTRY( ICONTITLELOGFONT, FW_NORMAL, METRICS_KEY, L"IconFont" );
static FONT_ENTRY( MENULOGFONT, FW_NORMAL, METRICS_KEY, L"MenuFont" );
static FONT_ENTRY( MESSAGELOGFONT, FW_NORMAL, METRICS_KEY, L"MessageFont" );
static FONT_ENTRY( SMCAPTIONLOGFONT, FW_NORMAL, METRICS_KEY, L"SmCaptionFont" );
static FONT_ENTRY( STATUSLOGFONT, FW_NORMAL, METRICS_KEY, L"StatusFont" );
static USERPREF_ENTRY( MENUANIMATION, 0, 0x02 );
static USERPREF_ENTRY( COMBOBOXANIMATION, 0, 0x04 );
static USERPREF_ENTRY( LISTBOXSMOOTHSCROLLING, 0, 0x08 );
static USERPREF_ENTRY( GRADIENTCAPTIONS, 0, 0x10 );
static USERPREF_ENTRY( KEYBOARDCUES, 0, 0x20 );
static USERPREF_ENTRY( ACTIVEWNDTRKZORDER, 0, 0x40 );
static USERPREF_ENTRY( HOTTRACKING, 0, 0x80 );
static USERPREF_ENTRY( MENUFADE, 1, 0x02 );
static USERPREF_ENTRY( SELECTIONFADE, 1, 0x04 );
static USERPREF_ENTRY( TOOLTIPANIMATION, 1, 0x08 );
static USERPREF_ENTRY( TOOLTIPFADE, 1, 0x10 );
static USERPREF_ENTRY( CURSORSHADOW, 1, 0x20 );
static USERPREF_ENTRY( MOUSESONAR, 1, 0x40 );
static USERPREF_ENTRY( MOUSECLICKLOCK, 1, 0x80 );
static USERPREF_ENTRY( MOUSEVANISH, 2, 0x01 );
static USERPREF_ENTRY( FLATMENU, 2, 0x02 );
static USERPREF_ENTRY( DROPSHADOW, 2, 0x04 );
static USERPREF_ENTRY( UIEFFECTS, 3, 0x80 );
static USERPREF_ENTRY( DISABLEOVERLAPPEDCONTENT, 4, 0x01 );
static USERPREF_ENTRY( CLIENTAREAANIMATION, 4, 0x02 );
static USERPREF_ENTRY( CLEARTYPE, 4, 0x10 );
static USERPREF_ENTRY( SPEECHRECOGNITION, 4, 0x20 );
static struct sysparam_rgb_entry system_colors[] =
{
#define RGB_ENTRY(name,val,reg) { { get_rgb_entry, set_rgb_entry, init_rgb_entry, COLORS_KEY, reg }, (val) }
RGB_ENTRY( COLOR_SCROLLBAR, RGB(212, 208, 200), L"Scrollbar" ),
RGB_ENTRY( COLOR_BACKGROUND, RGB(58, 110, 165), L"Background" ),
RGB_ENTRY( COLOR_ACTIVECAPTION, RGB(10, 36, 106), L"ActiveTitle" ),
RGB_ENTRY( COLOR_INACTIVECAPTION, RGB(128, 128, 128), L"InactiveTitle" ),
RGB_ENTRY( COLOR_MENU, RGB(212, 208, 200), L"Menu" ),
RGB_ENTRY( COLOR_WINDOW, RGB(255, 255, 255), L"Window" ),
RGB_ENTRY( COLOR_WINDOWFRAME, RGB(0, 0, 0), L"WindowFrame" ),
RGB_ENTRY( COLOR_MENUTEXT, RGB(0, 0, 0), L"MenuText" ),
RGB_ENTRY( COLOR_WINDOWTEXT, RGB(0, 0, 0), L"WindowText" ),
RGB_ENTRY( COLOR_CAPTIONTEXT, RGB(255, 255, 255), L"TitleText" ),
RGB_ENTRY( COLOR_ACTIVEBORDER, RGB(212, 208, 200), L"ActiveBorder" ),
RGB_ENTRY( COLOR_INACTIVEBORDER, RGB(212, 208, 200), L"InactiveBorder" ),
RGB_ENTRY( COLOR_APPWORKSPACE, RGB(128, 128, 128), L"AppWorkSpace" ),
RGB_ENTRY( COLOR_HIGHLIGHT, RGB(10, 36, 106), L"Hilight" ),
RGB_ENTRY( COLOR_HIGHLIGHTTEXT, RGB(255, 255, 255), L"HilightText" ),
RGB_ENTRY( COLOR_BTNFACE, RGB(212, 208, 200), L"ButtonFace" ),
RGB_ENTRY( COLOR_BTNSHADOW, RGB(128, 128, 128), L"ButtonShadow" ),
RGB_ENTRY( COLOR_GRAYTEXT, RGB(128, 128, 128), L"GrayText" ),
RGB_ENTRY( COLOR_BTNTEXT, RGB(0, 0, 0), L"ButtonText" ),
RGB_ENTRY( COLOR_INACTIVECAPTIONTEXT, RGB(212, 208, 200), L"InactiveTitleText" ),
RGB_ENTRY( COLOR_BTNHIGHLIGHT, RGB(255, 255, 255), L"ButtonHilight" ),
RGB_ENTRY( COLOR_3DDKSHADOW, RGB(64, 64, 64), L"ButtonDkShadow" ),
RGB_ENTRY( COLOR_3DLIGHT, RGB(212, 208, 200), L"ButtonLight" ),
RGB_ENTRY( COLOR_INFOTEXT, RGB(0, 0, 0), L"InfoText" ),
RGB_ENTRY( COLOR_INFOBK, RGB(255, 255, 225), L"InfoWindow" ),
RGB_ENTRY( COLOR_ALTERNATEBTNFACE, RGB(181, 181, 181), L"ButtonAlternateFace" ),
RGB_ENTRY( COLOR_HOTLIGHT, RGB(0, 0, 200), L"HotTrackingColor" ),
RGB_ENTRY( COLOR_GRADIENTACTIVECAPTION, RGB(166, 202, 240), L"GradientActiveTitle" ),
RGB_ENTRY( COLOR_GRADIENTINACTIVECAPTION, RGB(192, 192, 192), L"GradientInactiveTitle" ),
RGB_ENTRY( COLOR_MENUHILIGHT, RGB(10, 36, 106), L"MenuHilight" ),
RGB_ENTRY( COLOR_MENUBAR, RGB(212, 208, 200), L"MenuBar" )
#undef RGB_ENTRY
};
/* entries that are initialized by default in the registry */
static union sysparam_all_entry * const default_entries[] =
{
(union sysparam_all_entry *)&entry_ACTIVEWINDOWTRACKING,
(union sysparam_all_entry *)&entry_ACTIVEWNDTRKTIMEOUT,
(union sysparam_all_entry *)&entry_BEEP,
(union sysparam_all_entry *)&entry_BLOCKSENDINPUTRESETS,
(union sysparam_all_entry *)&entry_BORDER,
(union sysparam_all_entry *)&entry_CAPTIONHEIGHT,
(union sysparam_all_entry *)&entry_CAPTIONWIDTH,
(union sysparam_all_entry *)&entry_CARETWIDTH,
(union sysparam_all_entry *)&entry_DESKWALLPAPER,
(union sysparam_all_entry *)&entry_DOUBLECLICKTIME,
(union sysparam_all_entry *)&entry_DOUBLECLKHEIGHT,
(union sysparam_all_entry *)&entry_DOUBLECLKWIDTH,
(union sysparam_all_entry *)&entry_DRAGFULLWINDOWS,
(union sysparam_all_entry *)&entry_DRAGHEIGHT,
(union sysparam_all_entry *)&entry_DRAGWIDTH,
(union sysparam_all_entry *)&entry_FOCUSBORDERHEIGHT,
(union sysparam_all_entry *)&entry_FOCUSBORDERWIDTH,
(union sysparam_all_entry *)&entry_FONTSMOOTHING,
(union sysparam_all_entry *)&entry_FONTSMOOTHINGCONTRAST,
(union sysparam_all_entry *)&entry_FONTSMOOTHINGORIENTATION,
(union sysparam_all_entry *)&entry_FONTSMOOTHINGTYPE,
(union sysparam_all_entry *)&entry_FOREGROUNDFLASHCOUNT,
(union sysparam_all_entry *)&entry_FOREGROUNDLOCKTIMEOUT,
(union sysparam_all_entry *)&entry_ICONHORIZONTALSPACING,
(union sysparam_all_entry *)&entry_ICONTITLEWRAP,
(union sysparam_all_entry *)&entry_ICONVERTICALSPACING,
(union sysparam_all_entry *)&entry_KEYBOARDDELAY,
(union sysparam_all_entry *)&entry_KEYBOARDPREF,
(union sysparam_all_entry *)&entry_KEYBOARDSPEED,
(union sysparam_all_entry *)&entry_LOWPOWERACTIVE,
(union sysparam_all_entry *)&entry_MENUHEIGHT,
(union sysparam_all_entry *)&entry_MENUSHOWDELAY,
(union sysparam_all_entry *)&entry_MENUWIDTH,
(union sysparam_all_entry *)&entry_MOUSEACCELERATION,
(union sysparam_all_entry *)&entry_MOUSEBUTTONSWAP,
(union sysparam_all_entry *)&entry_MOUSECLICKLOCKTIME,
(union sysparam_all_entry *)&entry_MOUSEHOVERHEIGHT,
(union sysparam_all_entry *)&entry_MOUSEHOVERTIME,
(union sysparam_all_entry *)&entry_MOUSEHOVERWIDTH,
(union sysparam_all_entry *)&entry_MOUSESPEED,
(union sysparam_all_entry *)&entry_MOUSETHRESHOLD1,
(union sysparam_all_entry *)&entry_MOUSETHRESHOLD2,
(union sysparam_all_entry *)&entry_PADDEDBORDERWIDTH,
(union sysparam_all_entry *)&entry_SCREENREADER,
(union sysparam_all_entry *)&entry_SCROLLHEIGHT,
(union sysparam_all_entry *)&entry_SCROLLWIDTH,
(union sysparam_all_entry *)&entry_SHOWSOUNDS,
(union sysparam_all_entry *)&entry_SMCAPTIONHEIGHT,
(union sysparam_all_entry *)&entry_SMCAPTIONWIDTH,
(union sysparam_all_entry *)&entry_SNAPTODEFBUTTON,
(union sysparam_all_entry *)&entry_USERPREFERENCESMASK,
(union sysparam_all_entry *)&entry_WHEELSCROLLCHARS,
(union sysparam_all_entry *)&entry_WHEELSCROLLLINES,
(union sysparam_all_entry *)&entry_AUDIODESC_LOCALE,
(union sysparam_all_entry *)&entry_AUDIODESC_ON,
};
/***********************************************************************
* SYSPARAMS_Init
*/
void SYSPARAMS_Init(void)
{
HKEY key;
DWORD i, dispos, dpi_scaling;
/* this one must be non-volatile */
if (RegCreateKeyW( HKEY_CURRENT_USER, L"Software\\Wine", &key ))
{
ERR("Can't create wine registry branch\n");
return;
}
/* @@ Wine registry key: HKCU\Software\Wine\Temporary System Parameters */
if (RegCreateKeyExW( key, L"Temporary System Parameters", 0, 0,
REG_OPTION_VOLATILE, KEY_ALL_ACCESS, 0, &volatile_base_key, &dispos ))
ERR("Can't create non-permanent wine registry branch\n");
RegCloseKey( key );
get_dword_entry( (union sysparam_all_entry *)&entry_LOGPIXELS, 0, &system_dpi, 0 );
if (!system_dpi) /* check fallback key */
{
if (!RegOpenKeyW( HKEY_CURRENT_CONFIG, L"Software\\Fonts", &key ))
{
DWORD type, size = sizeof(system_dpi);
if (RegQueryValueExW( key, L"LogPixels", NULL, &type, (void *)&system_dpi, &size ) ||
type != REG_DWORD)
system_dpi = 0;
RegCloseKey( key );
}
}
if (!system_dpi) system_dpi = USER_DEFAULT_SCREEN_DPI;
/* FIXME: what do the DpiScalingVer flags mean? */
get_dword_entry( (union sysparam_all_entry *)&entry_DPISCALINGVER, 0, &dpi_scaling, 0 );
if (!dpi_scaling)
{
default_awareness = DPI_AWARENESS_PER_MONITOR_AWARE;
dpi_awareness = 0x10 | default_awareness;
}
if (volatile_base_key && dispos == REG_CREATED_NEW_KEY) /* first process, initialize entries */
{
for (i = 0; i < ARRAY_SIZE( default_entries ); i++)
default_entries[i]->hdr.init( default_entries[i] );
}
}
static BOOL update_desktop_wallpaper(void)
{
DWORD pid;
if (GetWindowThreadProcessId( GetDesktopWindow(), &pid ) && pid == GetCurrentProcessId())
{
WCHAR wallpaper[MAX_PATH], pattern[256];
entry_DESKWALLPAPER.hdr.loaded = entry_DESKPATTERN.hdr.loaded = FALSE;
if (get_entry( &entry_DESKWALLPAPER, MAX_PATH, wallpaper ) &&
get_entry( &entry_DESKPATTERN, 256, pattern ))
update_wallpaper( wallpaper, pattern );
}
else SendMessageW( GetDesktopWindow(), WM_SETTINGCHANGE, SPI_SETDESKWALLPAPER, 0 );
return TRUE;
}
/***********************************************************************
* SystemParametersInfoForDpi (USER32.@)
*/
BOOL WINAPI SystemParametersInfoForDpi( UINT action, UINT val, PVOID ptr, UINT winini, UINT dpi )
{
BOOL ret = FALSE;
switch (action)
{
case SPI_GETICONTITLELOGFONT:
ret = get_entry_dpi( &entry_ICONTITLELOGFONT, val, ptr, dpi );
break;
case SPI_GETNONCLIENTMETRICS:
{
NONCLIENTMETRICSW *ncm = ptr;
if (!ncm) break;
ret = get_entry_dpi( &entry_BORDER, 0, &ncm->iBorderWidth, dpi ) &&
get_entry_dpi( &entry_SCROLLWIDTH, 0, &ncm->iScrollWidth, dpi ) &&
get_entry_dpi( &entry_SCROLLHEIGHT, 0, &ncm->iScrollHeight, dpi ) &&
get_entry_dpi( &entry_CAPTIONWIDTH, 0, &ncm->iCaptionWidth, dpi ) &&
get_entry_dpi( &entry_CAPTIONHEIGHT, 0, &ncm->iCaptionHeight, dpi ) &&
get_entry_dpi( &entry_CAPTIONLOGFONT, 0, &ncm->lfCaptionFont, dpi ) &&
get_entry_dpi( &entry_SMCAPTIONWIDTH, 0, &ncm->iSmCaptionWidth, dpi ) &&
get_entry_dpi( &entry_SMCAPTIONHEIGHT, 0, &ncm->iSmCaptionHeight, dpi ) &&
get_entry_dpi( &entry_SMCAPTIONLOGFONT, 0, &ncm->lfSmCaptionFont, dpi ) &&
get_entry_dpi( &entry_MENUWIDTH, 0, &ncm->iMenuWidth, dpi ) &&
get_entry_dpi( &entry_MENUHEIGHT, 0, &ncm->iMenuHeight, dpi ) &&
get_entry_dpi( &entry_MENULOGFONT, 0, &ncm->lfMenuFont, dpi ) &&
get_entry_dpi( &entry_STATUSLOGFONT, 0, &ncm->lfStatusFont, dpi ) &&
get_entry_dpi( &entry_MESSAGELOGFONT, 0, &ncm->lfMessageFont, dpi );
if (ret && ncm->cbSize == sizeof(NONCLIENTMETRICSW))
ret = get_entry_dpi( &entry_PADDEDBORDERWIDTH, 0, &ncm->iPaddedBorderWidth, dpi );
normalize_nonclientmetrics( ncm );
break;
}
case SPI_GETICONMETRICS:
{
ICONMETRICSW *im = ptr;
if (im && im->cbSize == sizeof(*im))
ret = get_entry_dpi( &entry_ICONHORIZONTALSPACING, 0, &im->iHorzSpacing, dpi ) &&
get_entry_dpi( &entry_ICONVERTICALSPACING, 0, &im->iVertSpacing, dpi ) &&
get_entry_dpi( &entry_ICONTITLEWRAP, 0, &im->iTitleWrap, dpi ) &&
get_entry_dpi( &entry_ICONTITLELOGFONT, 0, &im->lfFont, dpi );
break;
}
default:
SetLastError( ERROR_INVALID_PARAMETER );
break;
}
return ret;
}
/***********************************************************************
* SystemParametersInfoW (USER32.@)
*
* Each system parameter has flag which shows whether the parameter
* is loaded or not. Parameters, stored directly in SysParametersInfo are
* loaded from registry only when they are requested and the flag is
* "false", after the loading the flag is set to "true". On interprocess
* notification of the parameter change the corresponding parameter flag is
* set to "false". The parameter value will be reloaded when it is requested
* the next time.
* Parameters, backed by or depend on GetSystemMetrics are processed
* differently. These parameters are always loaded. They are reloaded right
* away on interprocess change notification. We can't do lazy loading because
* we don't want to complicate GetSystemMetrics.
* Parameters, backed by X settings are read from corresponding setting.
* On the parameter change request the setting is changed. Interprocess change
* notifications are ignored.
* When parameter value is updated the changed value is stored in permanent
* registry branch if saving is requested. Otherwise it is stored
* in temporary branch
*
* Some SPI values can also be stored as Twips values in the registry,
* don't forget the conversion!
*/
BOOL WINAPI SystemParametersInfoW( UINT uiAction, UINT uiParam,
PVOID pvParam, UINT fWinIni )
{
#define WINE_SPI_FIXME(x) \
case x: \
{ \
static BOOL warn = TRUE; \
if (warn) \
{ \
warn = FALSE; \
FIXME( "Unimplemented action: %u (%s)\n", x, #x ); \
} \
} \
SetLastError( ERROR_INVALID_SPI_VALUE ); \
ret = FALSE; \
break
#define WINE_SPI_WARN(x) \
case x: \
WARN( "Ignored action: %u (%s)\n", x, #x ); \
ret = TRUE; \
break
BOOL ret = USER_Driver->pSystemParametersInfo( uiAction, uiParam, pvParam, fWinIni );
unsigned spi_idx = 0;
if (!ret) switch (uiAction)
{
case SPI_GETBEEP:
ret = get_entry( &entry_BEEP, uiParam, pvParam );
break;
case SPI_SETBEEP:
ret = set_entry( &entry_BEEP, uiParam, pvParam, fWinIni );
break;
case SPI_GETMOUSE:
ret = get_entry( &entry_MOUSETHRESHOLD1, uiParam, (INT *)pvParam ) &&
get_entry( &entry_MOUSETHRESHOLD2, uiParam, (INT *)pvParam + 1 ) &&
get_entry( &entry_MOUSEACCELERATION, uiParam, (INT *)pvParam + 2 );
break;
case SPI_SETMOUSE:
ret = set_entry( &entry_MOUSETHRESHOLD1, ((INT *)pvParam)[0], pvParam, fWinIni ) &&
set_entry( &entry_MOUSETHRESHOLD2, ((INT *)pvParam)[1], pvParam, fWinIni ) &&
set_entry( &entry_MOUSEACCELERATION, ((INT *)pvParam)[2], pvParam, fWinIni );
break;
case SPI_GETBORDER:
ret = get_entry( &entry_BORDER, uiParam, pvParam );
if (*(INT*)pvParam < 1) *(INT*)pvParam = 1;
break;
case SPI_SETBORDER:
ret = set_entry( &entry_BORDER, uiParam, pvParam, fWinIni );
break;
case SPI_GETKEYBOARDSPEED:
ret = get_entry( &entry_KEYBOARDSPEED, uiParam, pvParam );
break;
case SPI_SETKEYBOARDSPEED:
if (uiParam > 31) uiParam = 31;
ret = set_entry( &entry_KEYBOARDSPEED, uiParam, pvParam, fWinIni );
break;
/* not implemented in Windows */
WINE_SPI_WARN(SPI_LANGDRIVER); /* 12 */
case SPI_ICONHORIZONTALSPACING:
if (pvParam != NULL)
ret = get_entry( &entry_ICONHORIZONTALSPACING, uiParam, pvParam );
else
{
int min_val = map_to_dpi( 32, GetDpiForSystem() );
ret = set_entry( &entry_ICONHORIZONTALSPACING, max( min_val, uiParam ), pvParam, fWinIni );
}
break;
case SPI_GETSCREENSAVETIMEOUT:
ret = get_entry( &entry_SCREENSAVETIMEOUT, uiParam, pvParam );
break;
case SPI_SETSCREENSAVETIMEOUT:
ret = set_entry( &entry_SCREENSAVETIMEOUT, uiParam, pvParam, fWinIni );
break;
case SPI_GETSCREENSAVEACTIVE:
ret = get_entry( &entry_SCREENSAVEACTIVE, uiParam, pvParam );
break;
case SPI_SETSCREENSAVEACTIVE:
ret = set_entry( &entry_SCREENSAVEACTIVE, uiParam, pvParam, fWinIni );
break;
case SPI_GETGRIDGRANULARITY:
ret = get_entry( &entry_GRIDGRANULARITY, uiParam, pvParam );
break;
case SPI_SETGRIDGRANULARITY:
ret = set_entry( &entry_GRIDGRANULARITY, uiParam, pvParam, fWinIni );
break;
case SPI_SETDESKWALLPAPER:
if (!pvParam || set_entry( &entry_DESKWALLPAPER, uiParam, pvParam, fWinIni ))
ret = update_desktop_wallpaper();
break;
case SPI_SETDESKPATTERN:
if (!pvParam || set_entry( &entry_DESKPATTERN, uiParam, pvParam, fWinIni ))
ret = update_desktop_wallpaper();
break;
case SPI_GETKEYBOARDDELAY:
ret = get_entry( &entry_KEYBOARDDELAY, uiParam, pvParam );
break;
case SPI_SETKEYBOARDDELAY:
ret = set_entry( &entry_KEYBOARDDELAY, uiParam, pvParam, fWinIni );
break;
case SPI_ICONVERTICALSPACING:
if (pvParam != NULL)
ret = get_entry( &entry_ICONVERTICALSPACING, uiParam, pvParam );
else
{
int min_val = map_to_dpi( 32, GetDpiForSystem() );
ret = set_entry( &entry_ICONVERTICALSPACING, max( min_val, uiParam ), pvParam, fWinIni );
}
break;
case SPI_GETICONTITLEWRAP:
ret = get_entry( &entry_ICONTITLEWRAP, uiParam, pvParam );
break;
case SPI_SETICONTITLEWRAP:
ret = set_entry( &entry_ICONTITLEWRAP, uiParam, pvParam, fWinIni );
break;
case SPI_GETMENUDROPALIGNMENT:
ret = get_entry( &entry_MENUDROPALIGNMENT, uiParam, pvParam );
break;
case SPI_SETMENUDROPALIGNMENT:
ret = set_entry( &entry_MENUDROPALIGNMENT, uiParam, pvParam, fWinIni );
break;
case SPI_SETDOUBLECLKWIDTH:
ret = set_entry( &entry_DOUBLECLKWIDTH, uiParam, pvParam, fWinIni );
break;
case SPI_SETDOUBLECLKHEIGHT:
ret = set_entry( &entry_DOUBLECLKHEIGHT, uiParam, pvParam, fWinIni );
break;
case SPI_GETICONTITLELOGFONT:
ret = get_entry( &entry_ICONTITLELOGFONT, uiParam, pvParam );
break;
case SPI_SETDOUBLECLICKTIME:
ret = set_entry( &entry_DOUBLECLICKTIME, uiParam, pvParam, fWinIni );
break;
case SPI_SETMOUSEBUTTONSWAP:
ret = set_entry( &entry_MOUSEBUTTONSWAP, uiParam, pvParam, fWinIni );
break;
case SPI_SETICONTITLELOGFONT:
ret = set_entry( &entry_ICONTITLELOGFONT, uiParam, pvParam, fWinIni );
break;
case SPI_GETFASTTASKSWITCH: /* 35 */
if (!pvParam) return FALSE;
*(BOOL *)pvParam = TRUE;
ret = TRUE;
break;
case SPI_SETFASTTASKSWITCH: /* 36 */
/* the action is disabled */
ret = FALSE;
break;
case SPI_SETDRAGFULLWINDOWS:
ret = set_entry( &entry_DRAGFULLWINDOWS, uiParam, pvParam, fWinIni );
break;
case SPI_GETDRAGFULLWINDOWS:
ret = get_entry( &entry_DRAGFULLWINDOWS, uiParam, pvParam );
break;
case SPI_GETNONCLIENTMETRICS:
{
LPNONCLIENTMETRICSW lpnm = pvParam;
int padded_border;
if (!pvParam) return FALSE;
ret = get_entry( &entry_BORDER, 0, &lpnm->iBorderWidth ) &&
get_entry( &entry_PADDEDBORDERWIDTH, 0, &padded_border ) &&
get_entry( &entry_SCROLLWIDTH, 0, &lpnm->iScrollWidth ) &&
get_entry( &entry_SCROLLHEIGHT, 0, &lpnm->iScrollHeight ) &&
get_entry( &entry_CAPTIONWIDTH, 0, &lpnm->iCaptionWidth ) &&
get_entry( &entry_CAPTIONHEIGHT, 0, &lpnm->iCaptionHeight ) &&
get_entry( &entry_CAPTIONLOGFONT, 0, &lpnm->lfCaptionFont ) &&
get_entry( &entry_SMCAPTIONWIDTH, 0, &lpnm->iSmCaptionWidth ) &&
get_entry( &entry_SMCAPTIONHEIGHT, 0, &lpnm->iSmCaptionHeight ) &&
get_entry( &entry_SMCAPTIONLOGFONT, 0, &lpnm->lfSmCaptionFont ) &&
get_entry( &entry_MENUWIDTH, 0, &lpnm->iMenuWidth ) &&
get_entry( &entry_MENUHEIGHT, 0, &lpnm->iMenuHeight ) &&
get_entry( &entry_MENULOGFONT, 0, &lpnm->lfMenuFont ) &&
get_entry( &entry_STATUSLOGFONT, 0, &lpnm->lfStatusFont ) &&
get_entry( &entry_MESSAGELOGFONT, 0, &lpnm->lfMessageFont );
if (ret)
{
lpnm->iBorderWidth += padded_border;
if (lpnm->cbSize == sizeof(NONCLIENTMETRICSW)) lpnm->iPaddedBorderWidth = 0;
}
normalize_nonclientmetrics( lpnm );
break;
}
case SPI_SETNONCLIENTMETRICS:
{
LPNONCLIENTMETRICSW lpnm = pvParam;
int padded_border;
if (lpnm && (lpnm->cbSize == sizeof(NONCLIENTMETRICSW) ||
lpnm->cbSize == FIELD_OFFSET(NONCLIENTMETRICSW, iPaddedBorderWidth)))
{
get_entry( &entry_PADDEDBORDERWIDTH, 0, &padded_border );
ret = set_entry( &entry_BORDER, lpnm->iBorderWidth - padded_border, NULL, fWinIni ) &&
set_entry( &entry_SCROLLWIDTH, lpnm->iScrollWidth, NULL, fWinIni ) &&
set_entry( &entry_SCROLLHEIGHT, lpnm->iScrollHeight, NULL, fWinIni ) &&
set_entry( &entry_CAPTIONWIDTH, lpnm->iCaptionWidth, NULL, fWinIni ) &&
set_entry( &entry_CAPTIONHEIGHT, lpnm->iCaptionHeight, NULL, fWinIni ) &&
set_entry( &entry_SMCAPTIONWIDTH, lpnm->iSmCaptionWidth, NULL, fWinIni ) &&
set_entry( &entry_SMCAPTIONHEIGHT, lpnm->iSmCaptionHeight, NULL, fWinIni ) &&
set_entry( &entry_MENUWIDTH, lpnm->iMenuWidth, NULL, fWinIni ) &&
set_entry( &entry_MENUHEIGHT, lpnm->iMenuHeight, NULL, fWinIni ) &&
set_entry( &entry_MENULOGFONT, 0, &lpnm->lfMenuFont, fWinIni ) &&
set_entry( &entry_CAPTIONLOGFONT, 0, &lpnm->lfCaptionFont, fWinIni ) &&
set_entry( &entry_SMCAPTIONLOGFONT, 0, &lpnm->lfSmCaptionFont, fWinIni ) &&
set_entry( &entry_STATUSLOGFONT, 0, &lpnm->lfStatusFont, fWinIni ) &&
set_entry( &entry_MESSAGELOGFONT, 0, &lpnm->lfMessageFont, fWinIni );
}
break;
}
case SPI_GETMINIMIZEDMETRICS:
{
MINIMIZEDMETRICS * lpMm = pvParam;
if (lpMm && lpMm->cbSize == sizeof(*lpMm)) {
ret = get_entry( &entry_MINWIDTH, 0, &lpMm->iWidth ) &&
get_entry( &entry_MINHORZGAP, 0, &lpMm->iHorzGap ) &&
get_entry( &entry_MINVERTGAP, 0, &lpMm->iVertGap ) &&
get_entry( &entry_MINARRANGE, 0, &lpMm->iArrange );
lpMm->iWidth = max( 0, lpMm->iWidth );
lpMm->iHorzGap = max( 0, lpMm->iHorzGap );
lpMm->iVertGap = max( 0, lpMm->iVertGap );
lpMm->iArrange &= 0x0f;
}
break;
}
case SPI_SETMINIMIZEDMETRICS:
{
MINIMIZEDMETRICS * lpMm = pvParam;
if (lpMm && lpMm->cbSize == sizeof(*lpMm))
ret = set_entry( &entry_MINWIDTH, max( 0, lpMm->iWidth ), NULL, fWinIni ) &&
set_entry( &entry_MINHORZGAP, max( 0, lpMm->iHorzGap ), NULL, fWinIni ) &&
set_entry( &entry_MINVERTGAP, max( 0, lpMm->iVertGap ), NULL, fWinIni ) &&
set_entry( &entry_MINARRANGE, lpMm->iArrange & 0x0f, NULL, fWinIni );
break;
}
case SPI_GETICONMETRICS:
{
LPICONMETRICSW lpIcon = pvParam;
if(lpIcon && lpIcon->cbSize == sizeof(*lpIcon))
{
ret = get_entry( &entry_ICONHORIZONTALSPACING, 0, &lpIcon->iHorzSpacing ) &&
get_entry( &entry_ICONVERTICALSPACING, 0, &lpIcon->iVertSpacing ) &&
get_entry( &entry_ICONTITLEWRAP, 0, &lpIcon->iTitleWrap ) &&
get_entry( &entry_ICONTITLELOGFONT, 0, &lpIcon->lfFont );
}
break;
}
case SPI_SETICONMETRICS:
{
LPICONMETRICSW lpIcon = pvParam;
if (lpIcon && lpIcon->cbSize == sizeof(*lpIcon))
ret = set_entry( &entry_ICONVERTICALSPACING, max(32,lpIcon->iVertSpacing), NULL, fWinIni ) &&
set_entry( &entry_ICONHORIZONTALSPACING, max(32,lpIcon->iHorzSpacing), NULL, fWinIni ) &&
set_entry( &entry_ICONTITLEWRAP, lpIcon->iTitleWrap, NULL, fWinIni ) &&
set_entry( &entry_ICONTITLELOGFONT, 0, &lpIcon->lfFont, fWinIni );
break;
}
case SPI_SETWORKAREA: /* 47 WINVER >= 0x400 */
{
if (!pvParam) return FALSE;
spi_idx = SPI_SETWORKAREA_IDX;
work_area = *(RECT*)pvParam;
spi_loaded[spi_idx] = TRUE;
ret = TRUE;
break;
}
case SPI_GETWORKAREA: /* 48 WINVER >= 0x400 */
{
if (!pvParam) return FALSE;
spi_idx = SPI_SETWORKAREA_IDX;
if (!spi_loaded[spi_idx])
{
work_area = get_primary_monitor_rect();
EnumDisplayMonitors( 0, NULL, enum_monitors, (LPARAM)&work_area );
spi_loaded[spi_idx] = TRUE;
}
*(RECT*)pvParam = work_area;
ret = TRUE;
TRACE("work area %s\n", wine_dbgstr_rect( &work_area ));
break;
}
WINE_SPI_FIXME(SPI_SETPENWINDOWS); /* 49 WINVER >= 0x400 */
case SPI_GETFILTERKEYS: /* 50 */
{
LPFILTERKEYS lpFilterKeys = pvParam;
WARN("SPI_GETFILTERKEYS not fully implemented\n");
if (lpFilterKeys && lpFilterKeys->cbSize == sizeof(FILTERKEYS))
{
/* Indicate that no FilterKeys feature available */
lpFilterKeys->dwFlags = 0;
lpFilterKeys->iWaitMSec = 0;
lpFilterKeys->iDelayMSec = 0;
lpFilterKeys->iRepeatMSec = 0;
lpFilterKeys->iBounceMSec = 0;
ret = TRUE;
}
break;
}
WINE_SPI_FIXME(SPI_SETFILTERKEYS); /* 51 */
case SPI_GETTOGGLEKEYS: /* 52 */
{
LPTOGGLEKEYS lpToggleKeys = pvParam;
WARN("SPI_GETTOGGLEKEYS not fully implemented\n");
if (lpToggleKeys && lpToggleKeys->cbSize == sizeof(TOGGLEKEYS))
{
/* Indicate that no ToggleKeys feature available */
lpToggleKeys->dwFlags = 0;
ret = TRUE;
}
break;
}
WINE_SPI_FIXME(SPI_SETTOGGLEKEYS); /* 53 */
case SPI_GETMOUSEKEYS: /* 54 */
{
LPMOUSEKEYS lpMouseKeys = pvParam;
WARN("SPI_GETMOUSEKEYS not fully implemented\n");
if (lpMouseKeys && lpMouseKeys->cbSize == sizeof(MOUSEKEYS))
{
/* Indicate that no MouseKeys feature available */
lpMouseKeys->dwFlags = 0;
lpMouseKeys->iMaxSpeed = 360;
lpMouseKeys->iTimeToMaxSpeed = 1000;
lpMouseKeys->iCtrlSpeed = 0;
lpMouseKeys->dwReserved1 = 0;
lpMouseKeys->dwReserved2 = 0;
ret = TRUE;
}
break;
}
WINE_SPI_FIXME(SPI_SETMOUSEKEYS); /* 55 */
case SPI_GETSHOWSOUNDS:
ret = get_entry( &entry_SHOWSOUNDS, uiParam, pvParam );
break;
case SPI_SETSHOWSOUNDS:
ret = set_entry( &entry_SHOWSOUNDS, uiParam, pvParam, fWinIni );
break;
case SPI_GETSTICKYKEYS: /* 58 */
{
LPSTICKYKEYS lpStickyKeys = pvParam;
WARN("SPI_GETSTICKYKEYS not fully implemented\n");
if (lpStickyKeys && lpStickyKeys->cbSize == sizeof(STICKYKEYS))
{
/* Indicate that no StickyKeys feature available */
lpStickyKeys->dwFlags = 0;
ret = TRUE;
}
break;
}
WINE_SPI_FIXME(SPI_SETSTICKYKEYS); /* 59 */
case SPI_GETACCESSTIMEOUT: /* 60 */
{
LPACCESSTIMEOUT lpAccessTimeout = pvParam;
WARN("SPI_GETACCESSTIMEOUT not fully implemented\n");
if (lpAccessTimeout && lpAccessTimeout->cbSize == sizeof(ACCESSTIMEOUT))
{
/* Indicate that no accessibility features timeout is available */
lpAccessTimeout->dwFlags = 0;
lpAccessTimeout->iTimeOutMSec = 0;
ret = TRUE;
}
break;
}
WINE_SPI_FIXME(SPI_SETACCESSTIMEOUT); /* 61 */
case SPI_GETSERIALKEYS: /* 62 WINVER >= 0x400 */
{
LPSERIALKEYSW lpSerialKeysW = pvParam;
WARN("SPI_GETSERIALKEYS not fully implemented\n");
if (lpSerialKeysW && lpSerialKeysW->cbSize == sizeof(SERIALKEYSW))
{
/* Indicate that no SerialKeys feature available */
lpSerialKeysW->dwFlags = 0;
lpSerialKeysW->lpszActivePort = NULL;
lpSerialKeysW->lpszPort = NULL;
lpSerialKeysW->iBaudRate = 0;
lpSerialKeysW->iPortState = 0;
ret = TRUE;
}
break;
}
WINE_SPI_FIXME(SPI_SETSERIALKEYS); /* 63 WINVER >= 0x400 */
case SPI_GETSOUNDSENTRY: /* 64 */
{
LPSOUNDSENTRYW lpSoundSentryW = pvParam;
WARN("SPI_GETSOUNDSENTRY not fully implemented\n");
if (lpSoundSentryW && lpSoundSentryW->cbSize == sizeof(SOUNDSENTRYW))
{
/* Indicate that no SoundSentry feature available */
lpSoundSentryW->dwFlags = 0;
lpSoundSentryW->iFSTextEffect = 0;
lpSoundSentryW->iFSTextEffectMSec = 0;
lpSoundSentryW->iFSTextEffectColorBits = 0;
lpSoundSentryW->iFSGrafEffect = 0;
lpSoundSentryW->iFSGrafEffectMSec = 0;
lpSoundSentryW->iFSGrafEffectColor = 0;
lpSoundSentryW->iWindowsEffect = 0;
lpSoundSentryW->iWindowsEffectMSec = 0;
lpSoundSentryW->lpszWindowsEffectDLL = 0;
lpSoundSentryW->iWindowsEffectOrdinal = 0;
ret = TRUE;
}
break;
}
WINE_SPI_FIXME(SPI_SETSOUNDSENTRY); /* 65 */
case SPI_GETHIGHCONTRAST: /* 66 WINVER >= 0x400 */
{
LPHIGHCONTRASTW lpHighContrastW = pvParam;
WARN("SPI_GETHIGHCONTRAST not fully implemented\n");
if (lpHighContrastW && lpHighContrastW->cbSize == sizeof(HIGHCONTRASTW))
{
/* Indicate that no high contrast feature available */
lpHighContrastW->dwFlags = 0;
lpHighContrastW->lpszDefaultScheme = NULL;
ret = TRUE;
}
break;
}
WINE_SPI_FIXME(SPI_SETHIGHCONTRAST); /* 67 WINVER >= 0x400 */
case SPI_GETKEYBOARDPREF:
ret = get_entry( &entry_KEYBOARDPREF, uiParam, pvParam );
break;
case SPI_SETKEYBOARDPREF:
ret = set_entry( &entry_KEYBOARDPREF, uiParam, pvParam, fWinIni );
break;
case SPI_GETSCREENREADER:
ret = get_entry( &entry_SCREENREADER, uiParam, pvParam );
break;
case SPI_SETSCREENREADER:
ret = set_entry( &entry_SCREENREADER, uiParam, pvParam, fWinIni );
break;
case SPI_GETANIMATION: /* 72 WINVER >= 0x400 */
{
LPANIMATIONINFO lpAnimInfo = pvParam;
/* Tell it "disabled" */
if (lpAnimInfo && lpAnimInfo->cbSize == sizeof(ANIMATIONINFO))
{
lpAnimInfo->iMinAnimate = 0; /* Minimize and restore animation is disabled (nonzero == enabled) */
ret = TRUE;
}
break;
}
WINE_SPI_WARN(SPI_SETANIMATION); /* 73 WINVER >= 0x400 */
case SPI_GETFONTSMOOTHING:
ret = get_entry( &entry_FONTSMOOTHING, uiParam, pvParam );
if (ret) *(UINT *)pvParam = (*(UINT *)pvParam != 0);
break;
case SPI_SETFONTSMOOTHING:
uiParam = uiParam ? 2 : 0; /* Win NT4/2k/XP behavior */
ret = set_entry( &entry_FONTSMOOTHING, uiParam, pvParam, fWinIni );
break;
case SPI_SETDRAGWIDTH:
ret = set_entry( &entry_DRAGWIDTH, uiParam, pvParam, fWinIni );
break;
case SPI_SETDRAGHEIGHT:
ret = set_entry( &entry_DRAGHEIGHT, uiParam, pvParam, fWinIni );
break;
WINE_SPI_FIXME(SPI_SETHANDHELD); /* 78 WINVER >= 0x400 */
WINE_SPI_FIXME(SPI_GETLOWPOWERTIMEOUT); /* 79 WINVER >= 0x400 */
WINE_SPI_FIXME(SPI_GETPOWEROFFTIMEOUT); /* 80 WINVER >= 0x400 */
WINE_SPI_FIXME(SPI_SETLOWPOWERTIMEOUT); /* 81 WINVER >= 0x400 */
WINE_SPI_FIXME(SPI_SETPOWEROFFTIMEOUT); /* 82 WINVER >= 0x400 */
case SPI_GETLOWPOWERACTIVE:
ret = get_entry( &entry_LOWPOWERACTIVE, uiParam, pvParam );
break;
case SPI_SETLOWPOWERACTIVE:
ret = set_entry( &entry_LOWPOWERACTIVE, uiParam, pvParam, fWinIni );
break;
case SPI_GETPOWEROFFACTIVE:
ret = get_entry( &entry_POWEROFFACTIVE, uiParam, pvParam );
break;
case SPI_SETPOWEROFFACTIVE:
ret = set_entry( &entry_POWEROFFACTIVE, uiParam, pvParam, fWinIni );
break;
WINE_SPI_FIXME(SPI_SETCURSORS); /* 87 WINVER >= 0x400 */
WINE_SPI_FIXME(SPI_SETICONS); /* 88 WINVER >= 0x400 */
case SPI_GETDEFAULTINPUTLANG: /* 89 WINVER >= 0x400 */
ret = NtUserGetKeyboardLayout(0) != 0;
break;
WINE_SPI_FIXME(SPI_SETDEFAULTINPUTLANG); /* 90 WINVER >= 0x400 */
WINE_SPI_FIXME(SPI_SETLANGTOGGLE); /* 91 WINVER >= 0x400 */
case SPI_GETWINDOWSEXTENSION: /* 92 WINVER >= 0x400 */
WARN("pretend no support for Win9x Plus! for now.\n");
ret = FALSE; /* yes, this is the result value */
break;
case SPI_SETMOUSETRAILS:
ret = set_entry( &entry_MOUSETRAILS, uiParam, pvParam, fWinIni );
break;
case SPI_GETMOUSETRAILS:
ret = get_entry( &entry_MOUSETRAILS, uiParam, pvParam );
break;
case SPI_GETSNAPTODEFBUTTON:
ret = get_entry( &entry_SNAPTODEFBUTTON, uiParam, pvParam );
break;
case SPI_SETSNAPTODEFBUTTON:
ret = set_entry( &entry_SNAPTODEFBUTTON, uiParam, pvParam, fWinIni );
break;
case SPI_SETSCREENSAVERRUNNING:
ret = set_entry( &entry_SCREENSAVERRUNNING, uiParam, pvParam, fWinIni );
break;
case SPI_GETMOUSEHOVERWIDTH:
ret = get_entry( &entry_MOUSEHOVERWIDTH, uiParam, pvParam );
break;
case SPI_SETMOUSEHOVERWIDTH:
ret = set_entry( &entry_MOUSEHOVERWIDTH, uiParam, pvParam, fWinIni );
break;
case SPI_GETMOUSEHOVERHEIGHT:
ret = get_entry( &entry_MOUSEHOVERHEIGHT, uiParam, pvParam );
break;
case SPI_SETMOUSEHOVERHEIGHT:
ret = set_entry( &entry_MOUSEHOVERHEIGHT, uiParam, pvParam, fWinIni );
break;
case SPI_GETMOUSEHOVERTIME:
ret = get_entry( &entry_MOUSEHOVERTIME, uiParam, pvParam );
break;
case SPI_SETMOUSEHOVERTIME:
ret = set_entry( &entry_MOUSEHOVERTIME, uiParam, pvParam, fWinIni );
break;
case SPI_GETWHEELSCROLLLINES:
ret = get_entry( &entry_WHEELSCROLLLINES, uiParam, pvParam );
break;
case SPI_SETWHEELSCROLLLINES:
ret = set_entry( &entry_WHEELSCROLLLINES, uiParam, pvParam, fWinIni );
break;
case SPI_GETMENUSHOWDELAY:
ret = get_entry( &entry_MENUSHOWDELAY, uiParam, pvParam );
break;
case SPI_SETMENUSHOWDELAY:
ret = set_entry( &entry_MENUSHOWDELAY, uiParam, pvParam, fWinIni );
break;
case SPI_GETWHEELSCROLLCHARS:
ret = get_entry( &entry_WHEELSCROLLCHARS, uiParam, pvParam );
break;
case SPI_SETWHEELSCROLLCHARS:
ret = set_entry( &entry_WHEELSCROLLCHARS, uiParam, pvParam, fWinIni );
break;
WINE_SPI_FIXME(SPI_GETSHOWIMEUI); /* 110 _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
WINE_SPI_FIXME(SPI_SETSHOWIMEUI); /* 111 _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
case SPI_GETMOUSESPEED:
ret = get_entry( &entry_MOUSESPEED, uiParam, pvParam );
break;
case SPI_SETMOUSESPEED:
ret = set_entry( &entry_MOUSESPEED, uiParam, pvParam, fWinIni );
break;
case SPI_GETSCREENSAVERRUNNING:
ret = get_entry( &entry_SCREENSAVERRUNNING, uiParam, pvParam );
break;
case SPI_GETDESKWALLPAPER:
ret = get_entry( &entry_DESKWALLPAPER, uiParam, pvParam );
break;
case SPI_GETACTIVEWINDOWTRACKING:
ret = get_entry( &entry_ACTIVEWINDOWTRACKING, uiParam, pvParam );
break;
case SPI_SETACTIVEWINDOWTRACKING:
ret = set_entry( &entry_ACTIVEWINDOWTRACKING, uiParam, pvParam, fWinIni );
break;
case SPI_GETMENUANIMATION:
ret = get_entry( &entry_MENUANIMATION, uiParam, pvParam );
break;
case SPI_SETMENUANIMATION:
ret = set_entry( &entry_MENUANIMATION, uiParam, pvParam, fWinIni );
break;
case SPI_GETCOMBOBOXANIMATION:
ret = get_entry( &entry_COMBOBOXANIMATION, uiParam, pvParam );
break;
case SPI_SETCOMBOBOXANIMATION:
ret = set_entry( &entry_COMBOBOXANIMATION, uiParam, pvParam, fWinIni );
break;
case SPI_GETLISTBOXSMOOTHSCROLLING:
ret = get_entry( &entry_LISTBOXSMOOTHSCROLLING, uiParam, pvParam );
break;
case SPI_SETLISTBOXSMOOTHSCROLLING:
ret = set_entry( &entry_LISTBOXSMOOTHSCROLLING, uiParam, pvParam, fWinIni );
break;
case SPI_GETGRADIENTCAPTIONS:
ret = get_entry( &entry_GRADIENTCAPTIONS, uiParam, pvParam );
break;
case SPI_SETGRADIENTCAPTIONS:
ret = set_entry( &entry_GRADIENTCAPTIONS, uiParam, pvParam, fWinIni );
break;
case SPI_GETKEYBOARDCUES:
ret = get_entry( &entry_KEYBOARDCUES, uiParam, pvParam );
break;
case SPI_SETKEYBOARDCUES:
ret = set_entry( &entry_KEYBOARDCUES, uiParam, pvParam, fWinIni );
break;
case SPI_GETACTIVEWNDTRKZORDER:
ret = get_entry( &entry_ACTIVEWNDTRKZORDER, uiParam, pvParam );
break;
case SPI_SETACTIVEWNDTRKZORDER:
ret = set_entry( &entry_ACTIVEWNDTRKZORDER, uiParam, pvParam, fWinIni );
break;
case SPI_GETHOTTRACKING:
ret = get_entry( &entry_HOTTRACKING, uiParam, pvParam );
break;
case SPI_SETHOTTRACKING:
ret = set_entry( &entry_HOTTRACKING, uiParam, pvParam, fWinIni );
break;
case SPI_GETMENUFADE:
ret = get_entry( &entry_MENUFADE, uiParam, pvParam );
break;
case SPI_SETMENUFADE:
ret = set_entry( &entry_MENUFADE, uiParam, pvParam, fWinIni );
break;
case SPI_GETSELECTIONFADE:
ret = get_entry( &entry_SELECTIONFADE, uiParam, pvParam );
break;
case SPI_SETSELECTIONFADE:
ret = set_entry( &entry_SELECTIONFADE, uiParam, pvParam, fWinIni );
break;
case SPI_GETTOOLTIPANIMATION:
ret = get_entry( &entry_TOOLTIPANIMATION, uiParam, pvParam );
break;
case SPI_SETTOOLTIPANIMATION:
ret = set_entry( &entry_TOOLTIPANIMATION, uiParam, pvParam, fWinIni );
break;
case SPI_GETTOOLTIPFADE:
ret = get_entry( &entry_TOOLTIPFADE, uiParam, pvParam );
break;
case SPI_SETTOOLTIPFADE:
ret = set_entry( &entry_TOOLTIPFADE, uiParam, pvParam, fWinIni );
break;
case SPI_GETCURSORSHADOW:
ret = get_entry( &entry_CURSORSHADOW, uiParam, pvParam );
break;
case SPI_SETCURSORSHADOW:
ret = set_entry( &entry_CURSORSHADOW, uiParam, pvParam, fWinIni );
break;
case SPI_GETMOUSESONAR:
ret = get_entry( &entry_MOUSESONAR, uiParam, pvParam );
break;
case SPI_SETMOUSESONAR:
ret = set_entry( &entry_MOUSESONAR, uiParam, pvParam, fWinIni );
break;
case SPI_GETMOUSECLICKLOCK:
ret = get_entry( &entry_MOUSECLICKLOCK, uiParam, pvParam );
break;
case SPI_SETMOUSECLICKLOCK:
ret = set_entry( &entry_MOUSECLICKLOCK, uiParam, pvParam, fWinIni );
break;
case SPI_GETMOUSEVANISH:
ret = get_entry( &entry_MOUSEVANISH, uiParam, pvParam );
break;
case SPI_SETMOUSEVANISH:
ret = set_entry( &entry_MOUSEVANISH, uiParam, pvParam, fWinIni );
break;
case SPI_GETFLATMENU:
ret = get_entry( &entry_FLATMENU, uiParam, pvParam );
break;
case SPI_SETFLATMENU:
ret = set_entry( &entry_FLATMENU, uiParam, pvParam, fWinIni );
break;
case SPI_GETDROPSHADOW:
ret = get_entry( &entry_DROPSHADOW, uiParam, pvParam );
break;
case SPI_SETDROPSHADOW:
ret = set_entry( &entry_DROPSHADOW, uiParam, pvParam, fWinIni );
break;
case SPI_GETBLOCKSENDINPUTRESETS:
ret = get_entry( &entry_BLOCKSENDINPUTRESETS, uiParam, pvParam );
break;
case SPI_SETBLOCKSENDINPUTRESETS:
ret = set_entry( &entry_BLOCKSENDINPUTRESETS, uiParam, pvParam, fWinIni );
break;
case SPI_GETUIEFFECTS:
ret = get_entry( &entry_UIEFFECTS, uiParam, pvParam );
break;
case SPI_SETUIEFFECTS:
/* FIXME: this probably should mask other UI effect values when unset */
ret = set_entry( &entry_UIEFFECTS, uiParam, pvParam, fWinIni );
break;
case SPI_GETDISABLEOVERLAPPEDCONTENT:
ret = get_entry( &entry_DISABLEOVERLAPPEDCONTENT, uiParam, pvParam );
break;
case SPI_SETDISABLEOVERLAPPEDCONTENT:
ret = set_entry( &entry_DISABLEOVERLAPPEDCONTENT, uiParam, pvParam, fWinIni );
break;
case SPI_GETCLIENTAREAANIMATION:
ret = get_entry( &entry_CLIENTAREAANIMATION, uiParam, pvParam );
break;
case SPI_SETCLIENTAREAANIMATION:
ret = set_entry( &entry_CLIENTAREAANIMATION, uiParam, pvParam, fWinIni );
break;
case SPI_GETCLEARTYPE:
ret = get_entry( &entry_CLEARTYPE, uiParam, pvParam );
break;
case SPI_SETCLEARTYPE:
ret = set_entry( &entry_CLEARTYPE, uiParam, pvParam, fWinIni );
break;
case SPI_GETSPEECHRECOGNITION:
ret = get_entry( &entry_SPEECHRECOGNITION, uiParam, pvParam );
break;
case SPI_SETSPEECHRECOGNITION:
ret = set_entry( &entry_SPEECHRECOGNITION, uiParam, pvParam, fWinIni );
break;
case SPI_GETFOREGROUNDLOCKTIMEOUT:
ret = get_entry( &entry_FOREGROUNDLOCKTIMEOUT, uiParam, pvParam );
break;
case SPI_SETFOREGROUNDLOCKTIMEOUT:
/* FIXME: this should check that the calling thread
* is able to change the foreground window */
ret = set_entry( &entry_FOREGROUNDLOCKTIMEOUT, uiParam, pvParam, fWinIni );
break;
case SPI_GETACTIVEWNDTRKTIMEOUT:
ret = get_entry( &entry_ACTIVEWNDTRKTIMEOUT, uiParam, pvParam );
break;
case SPI_SETACTIVEWNDTRKTIMEOUT:
ret = get_entry( &entry_ACTIVEWNDTRKTIMEOUT, uiParam, pvParam );
break;
case SPI_GETFOREGROUNDFLASHCOUNT:
ret = get_entry( &entry_FOREGROUNDFLASHCOUNT, uiParam, pvParam );
break;
case SPI_SETFOREGROUNDFLASHCOUNT:
ret = set_entry( &entry_FOREGROUNDFLASHCOUNT, uiParam, pvParam, fWinIni );
break;
case SPI_GETCARETWIDTH:
ret = get_entry( &entry_CARETWIDTH, uiParam, pvParam );
break;
case SPI_SETCARETWIDTH:
ret = set_entry( &entry_CARETWIDTH, uiParam, pvParam, fWinIni );
break;
case SPI_GETMOUSECLICKLOCKTIME:
ret = get_entry( &entry_MOUSECLICKLOCKTIME, uiParam, pvParam );
break;
case SPI_SETMOUSECLICKLOCKTIME:
ret = set_entry( &entry_MOUSECLICKLOCKTIME, uiParam, pvParam, fWinIni );
break;
case SPI_GETFONTSMOOTHINGTYPE:
ret = get_entry( &entry_FONTSMOOTHINGTYPE, uiParam, pvParam );
break;
case SPI_SETFONTSMOOTHINGTYPE:
ret = set_entry( &entry_FONTSMOOTHINGTYPE, uiParam, pvParam, fWinIni );
break;
case SPI_GETFONTSMOOTHINGCONTRAST:
ret = get_entry( &entry_FONTSMOOTHINGCONTRAST, uiParam, pvParam );
break;
case SPI_SETFONTSMOOTHINGCONTRAST:
ret = set_entry( &entry_FONTSMOOTHINGCONTRAST, uiParam, pvParam, fWinIni );
break;
case SPI_GETFOCUSBORDERWIDTH:
ret = get_entry( &entry_FOCUSBORDERWIDTH, uiParam, pvParam );
break;
case SPI_GETFOCUSBORDERHEIGHT:
ret = get_entry( &entry_FOCUSBORDERHEIGHT, uiParam, pvParam );
break;
case SPI_SETFOCUSBORDERWIDTH:
ret = set_entry( &entry_FOCUSBORDERWIDTH, uiParam, pvParam, fWinIni );
break;
case SPI_SETFOCUSBORDERHEIGHT:
ret = set_entry( &entry_FOCUSBORDERHEIGHT, uiParam, pvParam, fWinIni );
break;
case SPI_GETFONTSMOOTHINGORIENTATION:
ret = get_entry( &entry_FONTSMOOTHINGORIENTATION, uiParam, pvParam );
break;
case SPI_SETFONTSMOOTHINGORIENTATION:
ret = set_entry( &entry_FONTSMOOTHINGORIENTATION, uiParam, pvParam, fWinIni );
break;
case SPI_GETAUDIODESCRIPTION:
{
AUDIODESCRIPTION *audio = pvParam;
if (audio && audio->cbSize == sizeof(AUDIODESCRIPTION) && uiParam == sizeof(AUDIODESCRIPTION) )
{
ret = get_entry( &entry_AUDIODESC_ON, 0, &audio->Enabled ) &&
get_entry( &entry_AUDIODESC_LOCALE, 0, &audio->Locale );
}
break;
}
case SPI_SETAUDIODESCRIPTION:
{
AUDIODESCRIPTION *audio = pvParam;
if (audio && audio->cbSize == sizeof(AUDIODESCRIPTION) && uiParam == sizeof(AUDIODESCRIPTION) )
{
ret = set_entry( &entry_AUDIODESC_ON, 0, &audio->Enabled, fWinIni) &&
set_entry( &entry_AUDIODESC_LOCALE, 0, &audio->Locale, fWinIni );
}
break;
}
default:
FIXME( "Unknown action: %u\n", uiAction );
SetLastError( ERROR_INVALID_SPI_VALUE );
ret = FALSE;
break;
}
if (ret)
SYSPARAMS_NotifyChange( uiAction, fWinIni );
TRACE("(%u, %u, %p, %u) ret %d\n",
uiAction, uiParam, pvParam, fWinIni, ret);
return ret;
#undef WINE_SPI_FIXME
#undef WINE_SPI_WARN
}
/***********************************************************************
* SystemParametersInfoA (USER32.@)
*/
BOOL WINAPI SystemParametersInfoA( UINT uiAction, UINT uiParam,
PVOID pvParam, UINT fuWinIni )
{
BOOL ret;
TRACE("(%u, %u, %p, %u)\n", uiAction, uiParam, pvParam, fuWinIni);
switch (uiAction)
{
case SPI_SETDESKWALLPAPER: /* 20 */
case SPI_SETDESKPATTERN: /* 21 */
{
WCHAR buffer[256];
if (pvParam)
if (!MultiByteToWideChar( CP_ACP, 0, pvParam, -1, buffer, ARRAY_SIZE( buffer )))
buffer[ARRAY_SIZE(buffer)-1] = 0;
ret = SystemParametersInfoW( uiAction, uiParam, pvParam ? buffer : NULL, fuWinIni );
break;
}
case SPI_GETICONTITLELOGFONT: /* 31 */
{
LOGFONTW tmp;
ret = SystemParametersInfoW( uiAction, uiParam, pvParam ? &tmp : NULL, fuWinIni );
if (ret && pvParam)
SYSPARAMS_LogFont32WTo32A( &tmp, pvParam );
break;
}
case SPI_GETNONCLIENTMETRICS: /* 41 WINVER >= 0x400 */
{
NONCLIENTMETRICSW tmp;
LPNONCLIENTMETRICSA lpnmA = pvParam;
if (lpnmA && (lpnmA->cbSize == sizeof(NONCLIENTMETRICSA) ||
lpnmA->cbSize == FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth)))
{
tmp.cbSize = sizeof(NONCLIENTMETRICSW);
ret = SystemParametersInfoW( uiAction, uiParam, &tmp, fuWinIni );
if (ret)
SYSPARAMS_NonClientMetrics32WTo32A( &tmp, lpnmA );
}
else
ret = FALSE;
break;
}
case SPI_SETNONCLIENTMETRICS: /* 42 WINVER >= 0x400 */
{
NONCLIENTMETRICSW tmp;
LPNONCLIENTMETRICSA lpnmA = pvParam;
if (lpnmA && (lpnmA->cbSize == sizeof(NONCLIENTMETRICSA) ||
lpnmA->cbSize == FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth)))
{
tmp.cbSize = sizeof(NONCLIENTMETRICSW);
SYSPARAMS_NonClientMetrics32ATo32W( lpnmA, &tmp );
ret = SystemParametersInfoW( uiAction, uiParam, &tmp, fuWinIni );
}
else
ret = FALSE;
break;
}
case SPI_GETICONMETRICS: /* 45 WINVER >= 0x400 */
{
ICONMETRICSW tmp;
LPICONMETRICSA lpimA = pvParam;
if (lpimA && lpimA->cbSize == sizeof(ICONMETRICSA))
{
tmp.cbSize = sizeof(ICONMETRICSW);
ret = SystemParametersInfoW( uiAction, uiParam, &tmp, fuWinIni );
if (ret)
{
lpimA->iHorzSpacing = tmp.iHorzSpacing;
lpimA->iVertSpacing = tmp.iVertSpacing;
lpimA->iTitleWrap = tmp.iTitleWrap;
SYSPARAMS_LogFont32WTo32A( &tmp.lfFont, &lpimA->lfFont );
}
}
else
ret = FALSE;
break;
}
case SPI_SETICONMETRICS: /* 46 WINVER >= 0x400 */
{
ICONMETRICSW tmp;
LPICONMETRICSA lpimA = pvParam;
if (lpimA && lpimA->cbSize == sizeof(ICONMETRICSA))
{
tmp.cbSize = sizeof(ICONMETRICSW);
tmp.iHorzSpacing = lpimA->iHorzSpacing;
tmp.iVertSpacing = lpimA->iVertSpacing;
tmp.iTitleWrap = lpimA->iTitleWrap;
SYSPARAMS_LogFont32ATo32W( &lpimA->lfFont, &tmp.lfFont);
ret = SystemParametersInfoW( uiAction, uiParam, &tmp, fuWinIni );
}
else
ret = FALSE;
break;
}
case SPI_GETHIGHCONTRAST: /* 66 WINVER >= 0x400 */
{
HIGHCONTRASTW tmp;
LPHIGHCONTRASTA lphcA = pvParam;
if (lphcA && lphcA->cbSize == sizeof(HIGHCONTRASTA))
{
tmp.cbSize = sizeof(HIGHCONTRASTW);
ret = SystemParametersInfoW( uiAction, uiParam, &tmp, fuWinIni );
if (ret)
{
lphcA->dwFlags = tmp.dwFlags;
lphcA->lpszDefaultScheme = NULL; /* FIXME? */
}
}
else
ret = FALSE;
break;
}
case SPI_GETDESKWALLPAPER: /* 115 */
{
WCHAR buffer[MAX_PATH];
ret = (SystemParametersInfoW( SPI_GETDESKWALLPAPER, uiParam, buffer, fuWinIni ) &&
WideCharToMultiByte(CP_ACP, 0, buffer, -1, pvParam, uiParam, NULL, NULL));
break;
}
default:
ret = SystemParametersInfoW( uiAction, uiParam, pvParam, fuWinIni );
break;
}
return ret;
}
/***********************************************************************
* GetSystemMetrics (USER32.@)
*/
INT WINAPI GetSystemMetrics( INT index )
{
NONCLIENTMETRICSW ncm;
MINIMIZEDMETRICS mm;
ICONMETRICSW im;
RECT rect;
UINT ret;
HDC hdc;
/* some metrics are dynamic */
switch (index)
{
case SM_CXVSCROLL:
case SM_CYHSCROLL:
get_entry( &entry_SCROLLWIDTH, 0, &ret );
return max( ret, 8 );
case SM_CYCAPTION:
ncm.cbSize = sizeof(ncm);
SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
return ncm.iCaptionHeight + 1;
case SM_CXBORDER:
case SM_CYBORDER:
/* SM_C{X,Y}BORDER always returns 1 regardless of 'BorderWidth' value in registry */
return 1;
case SM_CXDLGFRAME:
case SM_CYDLGFRAME:
return 3;
case SM_CYVTHUMB:
case SM_CXHTHUMB:
case SM_CYVSCROLL:
case SM_CXHSCROLL:
get_entry( &entry_SCROLLHEIGHT, 0, &ret );
return max( ret, 8 );
case SM_CXICON:
case SM_CYICON:
return map_to_dpi( 32, GetDpiForSystem() );
case SM_CXCURSOR:
case SM_CYCURSOR:
ret = map_to_dpi( 32, GetDpiForSystem() );
if (ret >= 64) return 64;
if (ret >= 48) return 48;
return 32;
case SM_CYMENU:
ncm.cbSize = sizeof(ncm);
SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
return ncm.iMenuHeight + 1;
case SM_CXFULLSCREEN:
/* see the remark for SM_CXMAXIMIZED, at least this formulation is
* correct */
return GetSystemMetrics( SM_CXMAXIMIZED) - 2 * GetSystemMetrics( SM_CXFRAME);
case SM_CYFULLSCREEN:
/* 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_DEBUG:
return 0;
case SM_SWAPBUTTON:
get_entry( &entry_MOUSEBUTTONSWAP, 0, &ret );
return ret;
case SM_RESERVED1:
case SM_RESERVED2:
case SM_RESERVED3:
case SM_RESERVED4:
return 0;
case SM_CXMIN:
ncm.cbSize = sizeof(ncm);
SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
hdc = get_display_dc();
get_text_metr_size( hdc, &ncm.lfCaptionFont, NULL, &ret );
release_display_dc( hdc );
return 3 * ncm.iCaptionWidth + ncm.iCaptionHeight + 4 * ret + 2 * GetSystemMetrics(SM_CXFRAME) + 4;
case SM_CYMIN:
return GetSystemMetrics( SM_CYCAPTION) + 2 * GetSystemMetrics( SM_CYFRAME);
case SM_CXSIZE:
get_entry( &entry_CAPTIONWIDTH, 0, &ret );
return max( ret, 8 );
case SM_CYSIZE:
ncm.cbSize = sizeof(ncm);
SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
return ncm.iCaptionHeight;
case SM_CXFRAME:
get_entry( &entry_BORDER, 0, &ret );
ret = max( ret, 1 );
return GetSystemMetrics(SM_CXDLGFRAME) + ret;
case SM_CYFRAME:
get_entry( &entry_BORDER, 0, &ret );
ret = max( ret, 1 );
return GetSystemMetrics(SM_CYDLGFRAME) + ret;
case SM_CXMINTRACK:
return GetSystemMetrics(SM_CXMIN);
case SM_CYMINTRACK:
return GetSystemMetrics(SM_CYMIN);
case SM_CXDOUBLECLK:
get_entry( &entry_DOUBLECLKWIDTH, 0, &ret );
return ret;
case SM_CYDOUBLECLK:
get_entry( &entry_DOUBLECLKHEIGHT, 0, &ret );
return ret;
case SM_CXICONSPACING:
im.cbSize = sizeof(im);
SystemParametersInfoW( SPI_GETICONMETRICS, sizeof(im), &im, 0 );
return im.iHorzSpacing;
case SM_CYICONSPACING:
im.cbSize = sizeof(im);
SystemParametersInfoW( SPI_GETICONMETRICS, sizeof(im), &im, 0 );
return im.iVertSpacing;
case SM_MENUDROPALIGNMENT:
SystemParametersInfoW( SPI_GETMENUDROPALIGNMENT, 0, &ret, 0 );
return ret;
case SM_PENWINDOWS:
return 0;
case SM_DBCSENABLED:
{
CPINFO cpinfo;
GetCPInfo( CP_ACP, &cpinfo );
return (cpinfo.MaxCharSize > 1);
}
case SM_CMOUSEBUTTONS:
return 3;
case SM_SECURE:
return 0;
case SM_CXEDGE:
return GetSystemMetrics(SM_CXBORDER) + 1;
case SM_CYEDGE:
return GetSystemMetrics(SM_CYBORDER) + 1;
case SM_CXMINSPACING:
mm.cbSize = sizeof(mm);
SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
return GetSystemMetrics(SM_CXMINIMIZED) + mm.iHorzGap;
case SM_CYMINSPACING:
mm.cbSize = sizeof(mm);
SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
return GetSystemMetrics(SM_CYMINIMIZED) + mm.iVertGap;
case SM_CXSMICON:
case SM_CYSMICON:
return map_to_dpi( 16, GetDpiForSystem() ) & ~1;
case SM_CYSMCAPTION:
ncm.cbSize = sizeof(ncm);
SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
return ncm.iSmCaptionHeight + 1;
case SM_CXSMSIZE:
get_entry( &entry_SMCAPTIONWIDTH, 0, &ret );
return ret;
case SM_CYSMSIZE:
ncm.cbSize = sizeof(ncm);
SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
return ncm.iSmCaptionHeight;
case SM_CXMENUSIZE:
get_entry( &entry_MENUWIDTH, 0, &ret );
return ret;
case SM_CYMENUSIZE:
ncm.cbSize = sizeof(ncm);
SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
return ncm.iMenuHeight;
case SM_ARRANGE:
mm.cbSize = sizeof(mm);
SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
return mm.iArrange;
case SM_CXMINIMIZED:
mm.cbSize = sizeof(mm);
SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
return mm.iWidth + 6;
case SM_CYMINIMIZED:
ncm.cbSize = sizeof(ncm);
SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
return ncm.iCaptionHeight + 6;
case SM_CXMAXTRACK:
return GetSystemMetrics(SM_CXVIRTUALSCREEN) + 4 + 2 * GetSystemMetrics(SM_CXFRAME);
case SM_CYMAXTRACK:
return GetSystemMetrics(SM_CYVIRTUALSCREEN) + 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:
/* 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:
return 0; /* 0 = ok, 1 = failsafe, 2 = failsafe + network */
case SM_CXDRAG:
get_entry( &entry_DRAGWIDTH, 0, &ret );
return ret;
case SM_CYDRAG:
get_entry( &entry_DRAGHEIGHT, 0, &ret );
return ret;
case SM_SHOWSOUNDS:
get_entry( &entry_SHOWSOUNDS, 0, &ret );
return ret;
case SM_CXMENUCHECK:
case SM_CYMENUCHECK:
{
TEXTMETRICW tm;
ncm.cbSize = sizeof(ncm);
SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
hdc = get_display_dc();
get_text_metr_size( hdc, &ncm.lfMenuFont, &tm, NULL);
release_display_dc( hdc );
return tm.tmHeight <= 0 ? 13 : ((tm.tmHeight + tm.tmExternalLeading + 1) / 2) * 2 - 1;
}
case SM_SLOWMACHINE:
return 0; /* Never true */
case SM_MIDEASTENABLED:
return 0; /* FIXME */
case SM_MOUSEWHEELPRESENT:
return 1;
case SM_CXSCREEN:
rect = get_primary_monitor_rect();
return rect.right - rect.left;
case SM_CYSCREEN:
rect = get_primary_monitor_rect();
return rect.bottom - rect.top;
case SM_XVIRTUALSCREEN:
rect = get_virtual_screen_rect();
return rect.left;
case SM_YVIRTUALSCREEN:
rect = get_virtual_screen_rect();
return rect.top;
case SM_CXVIRTUALSCREEN:
rect = get_virtual_screen_rect();
return rect.right - rect.left;
case SM_CYVIRTUALSCREEN:
rect = get_virtual_screen_rect();
return rect.bottom - rect.top;
case SM_CMONITORS:
return get_monitor_count();
case SM_SAMEDISPLAYFORMAT:
return 1;
case SM_IMMENABLED:
return 0; /* FIXME */
case SM_CXFOCUSBORDER:
case SM_CYFOCUSBORDER:
return 1;
case SM_TABLETPC:
case SM_MEDIACENTER:
return 0;
case SM_CMETRICS:
return SM_CMETRICS;
default:
return 0;
}
}
/***********************************************************************
* GetSystemMetricsForDpi (USER32.@)
*/
INT WINAPI GetSystemMetricsForDpi( INT index, UINT dpi )
{
NONCLIENTMETRICSW ncm;
ICONMETRICSW im;
UINT ret;
HDC hdc;
/* some metrics are dynamic */
switch (index)
{
case SM_CXVSCROLL:
case SM_CYHSCROLL:
get_entry_dpi( &entry_SCROLLWIDTH, 0, &ret, dpi );
return max( ret, 8 );
case SM_CYCAPTION:
ncm.cbSize = sizeof(ncm);
SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
return ncm.iCaptionHeight + 1;
case SM_CYVTHUMB:
case SM_CXHTHUMB:
case SM_CYVSCROLL:
case SM_CXHSCROLL:
get_entry_dpi( &entry_SCROLLHEIGHT, 0, &ret, dpi );
return max( ret, 8 );
case SM_CXICON:
case SM_CYICON:
return map_to_dpi( 32, dpi );
case SM_CXCURSOR:
case SM_CYCURSOR:
ret = map_to_dpi( 32, dpi );
if (ret >= 64) return 64;
if (ret >= 48) return 48;
return 32;
case SM_CYMENU:
ncm.cbSize = sizeof(ncm);
SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
return ncm.iMenuHeight + 1;
case SM_CXSIZE:
get_entry_dpi( &entry_CAPTIONWIDTH, 0, &ret, dpi );
return max( ret, 8 );
case SM_CYSIZE:
ncm.cbSize = sizeof(ncm);
SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
return ncm.iCaptionHeight;
case SM_CXFRAME:
get_entry_dpi( &entry_BORDER, 0, &ret, dpi );
ret = max( ret, 1 );
return GetSystemMetricsForDpi( SM_CXDLGFRAME, dpi ) + ret;
case SM_CYFRAME:
get_entry_dpi( &entry_BORDER, 0, &ret, dpi );
ret = max( ret, 1 );
return GetSystemMetricsForDpi( SM_CYDLGFRAME, dpi ) + ret;
case SM_CXICONSPACING:
im.cbSize = sizeof(im);
SystemParametersInfoForDpi( SPI_GETICONMETRICS, sizeof(im), &im, 0, dpi );
return im.iHorzSpacing;
case SM_CYICONSPACING:
im.cbSize = sizeof(im);
SystemParametersInfoForDpi( SPI_GETICONMETRICS, sizeof(im), &im, 0, dpi );
return im.iVertSpacing;
case SM_CXSMICON:
case SM_CYSMICON:
return map_to_dpi( 16, dpi ) & ~1;
case SM_CYSMCAPTION:
ncm.cbSize = sizeof(ncm);
SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
return ncm.iSmCaptionHeight + 1;
case SM_CXSMSIZE:
get_entry_dpi( &entry_SMCAPTIONWIDTH, 0, &ret, dpi );
return ret;
case SM_CYSMSIZE:
ncm.cbSize = sizeof(ncm);
SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
return ncm.iSmCaptionHeight;
case SM_CXMENUSIZE:
get_entry_dpi( &entry_MENUWIDTH, 0, &ret, dpi );
return ret;
case SM_CYMENUSIZE:
ncm.cbSize = sizeof(ncm);
SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
return ncm.iMenuHeight;
case SM_CXMENUCHECK:
case SM_CYMENUCHECK:
{
TEXTMETRICW tm;
ncm.cbSize = sizeof(ncm);
SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
hdc = get_display_dc();
get_text_metr_size( hdc, &ncm.lfMenuFont, &tm, NULL);
release_display_dc( hdc );
return tm.tmHeight <= 0 ? 13 : ((tm.tmHeight + tm.tmExternalLeading - 1) | 1);
}
default:
return GetSystemMetrics( index );
}
}
/***********************************************************************
* SwapMouseButton (USER32.@)
* Reverse or restore the meaning of the left and right mouse buttons
* fSwap [I ] TRUE - reverse, FALSE - original
* RETURN
* previous state
*/
BOOL WINAPI SwapMouseButton( BOOL fSwap )
{
BOOL prev = GetSystemMetrics(SM_SWAPBUTTON);
SystemParametersInfoW(SPI_SETMOUSEBUTTONSWAP, fSwap, 0, 0);
return prev;
}
/**********************************************************************
* SetDoubleClickTime (USER32.@)
*/
BOOL WINAPI SetDoubleClickTime( UINT interval )
{
return SystemParametersInfoW(SPI_SETDOUBLECLICKTIME, interval, 0, 0);
}
/**********************************************************************
* GetDoubleClickTime (USER32.@)
*/
UINT WINAPI GetDoubleClickTime(void)
{
UINT time = 0;
get_entry( &entry_DOUBLECLICKTIME, 0, &time );
if (!time) time = 500;
return time;
}
/*************************************************************************
* GetSysColor (USER32.@)
*/
COLORREF WINAPI DECLSPEC_HOTPATCH GetSysColor( INT nIndex )
{
COLORREF ret = 0;
if (nIndex >= 0 && nIndex < ARRAY_SIZE( system_colors ))
get_entry( &system_colors[nIndex], 0, &ret );
return ret;
}
/*************************************************************************
* SetSysColors (USER32.@)
*/
BOOL WINAPI SetSysColors( INT count, const INT *colors, const COLORREF *values )
{
int i;
if (IS_INTRESOURCE(colors)) return FALSE; /* stupid app passes a color instead of an array */
for (i = 0; i < count; i++)
if (colors[i] >= 0 && colors[i] <= ARRAY_SIZE( system_colors ))
set_entry( &system_colors[colors[i]], values[i], 0, 0 );
/* Send WM_SYSCOLORCHANGE message to all windows */
SendMessageTimeoutW( HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0, SMTO_ABORTIFHUNG, 2000, NULL );
/* Repaint affected portions of all visible windows */
RedrawWindow( 0, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN );
return TRUE;
}
/*************************************************************************
* SetSysColorsTemp (USER32.@)
*/
DWORD_PTR WINAPI SetSysColorsTemp( const COLORREF *pPens, const HBRUSH *pBrushes, DWORD_PTR n)
{
FIXME( "no longer supported\n" );
return FALSE;
}
/***********************************************************************
* GetSysColorBrush (USER32.@)
*/
HBRUSH WINAPI DECLSPEC_HOTPATCH GetSysColorBrush( INT index )
{
if (index < 0 || index >= ARRAY_SIZE( system_colors )) return 0;
if (!system_colors[index].brush)
{
HBRUSH brush = CreateSolidBrush( GetSysColor( index ));
__wine_make_gdi_object_system( brush, TRUE );
if (InterlockedCompareExchangePointer( (void **)&system_colors[index].brush, brush, 0 ))
{
__wine_make_gdi_object_system( brush, FALSE );
DeleteObject( brush );
}
}
return system_colors[index].brush;
}
/***********************************************************************
* SYSCOLOR_GetPen
*/
HPEN SYSCOLOR_GetPen( INT index )
{
/* We can assert here, because this function is internal to Wine */
assert (0 <= index && index < ARRAY_SIZE( system_colors ));
if (!system_colors[index].pen)
{
HPEN pen = CreatePen( PS_SOLID, 1, GetSysColor( index ));
__wine_make_gdi_object_system( pen, TRUE );
if (InterlockedCompareExchangePointer( (void **)&system_colors[index].pen, pen, 0 ))
{
__wine_make_gdi_object_system( pen, FALSE );
DeleteObject( pen );
}
}
return system_colors[index].pen;
}
/***********************************************************************
* SYSCOLOR_Get55AABrush
*/
HBRUSH SYSCOLOR_Get55AABrush(void)
{
static const WORD pattern[] = { 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa };
static HBRUSH brush_55aa;
if (!brush_55aa)
{
HBITMAP bitmap = CreateBitmap( 8, 8, 1, 1, pattern );
HBRUSH brush = CreatePatternBrush( bitmap );
DeleteObject( bitmap );
__wine_make_gdi_object_system( brush, TRUE );
if (InterlockedCompareExchangePointer( (void **)&brush_55aa, brush, 0 ))
{
__wine_make_gdi_object_system( brush, FALSE );
DeleteObject( brush );
}
}
return brush_55aa;
}
/***********************************************************************
* ChangeDisplaySettingsA (USER32.@)
*/
LONG WINAPI ChangeDisplaySettingsA( LPDEVMODEA devmode, DWORD flags )
{
if (devmode) devmode->dmDriverExtra = 0;
return ChangeDisplaySettingsExA(NULL,devmode,NULL,flags,NULL);
}
/***********************************************************************
* ChangeDisplaySettingsW (USER32.@)
*/
LONG WINAPI ChangeDisplaySettingsW( LPDEVMODEW devmode, DWORD flags )
{
if (devmode) devmode->dmDriverExtra = 0;
return ChangeDisplaySettingsExW(NULL,devmode,NULL,flags,NULL);
}
/***********************************************************************
* ChangeDisplaySettingsExA (USER32.@)
*/
LONG WINAPI ChangeDisplaySettingsExA( LPCSTR devname, LPDEVMODEA devmode, HWND hwnd,
DWORD flags, LPVOID lparam )
{
LONG ret;
UNICODE_STRING nameW;
if (devname) RtlCreateUnicodeStringFromAsciiz(&nameW, devname);
else nameW.Buffer = NULL;
if (devmode)
{
DEVMODEW *devmodeW;
devmodeW = GdiConvertToDevmodeW(devmode);
if (devmodeW)
{
ret = ChangeDisplaySettingsExW(nameW.Buffer, devmodeW, hwnd, flags, lparam);
HeapFree(GetProcessHeap(), 0, devmodeW);
}
else
ret = DISP_CHANGE_SUCCESSFUL;
}
else
{
ret = ChangeDisplaySettingsExW(nameW.Buffer, NULL, hwnd, flags, lparam);
}
if (devname) RtlFreeUnicodeString(&nameW);
return ret;
}
#define _X_FIELD(prefix, bits) \
if ((fields) & prefix##_##bits) \
{ \
p += sprintf(p, "%s%s", first ? "" : ",", #bits); \
first = FALSE; \
}
static const CHAR *_CDS_flags(DWORD fields)
{
BOOL first = TRUE;
CHAR buf[128];
CHAR *p = buf;
_X_FIELD(CDS, UPDATEREGISTRY)
_X_FIELD(CDS, TEST)
_X_FIELD(CDS, FULLSCREEN)
_X_FIELD(CDS, GLOBAL)
_X_FIELD(CDS, SET_PRIMARY)
_X_FIELD(CDS, VIDEOPARAMETERS)
_X_FIELD(CDS, ENABLE_UNSAFE_MODES)
_X_FIELD(CDS, DISABLE_UNSAFE_MODES)
_X_FIELD(CDS, RESET)
_X_FIELD(CDS, RESET_EX)
_X_FIELD(CDS, NORESET)
*p = 0;
return wine_dbg_sprintf("%s", buf);
}
static const CHAR *_DM_fields(DWORD fields)
{
BOOL first = TRUE;
CHAR buf[128];
CHAR *p = buf;
_X_FIELD(DM, BITSPERPEL)
_X_FIELD(DM, PELSWIDTH)
_X_FIELD(DM, PELSHEIGHT)
_X_FIELD(DM, DISPLAYFLAGS)
_X_FIELD(DM, DISPLAYFREQUENCY)
_X_FIELD(DM, POSITION)
_X_FIELD(DM, DISPLAYORIENTATION)
*p = 0;
return wine_dbg_sprintf("%s", buf);
}
#undef _X_FIELD
static void trace_devmode(const DEVMODEW *devmode)
{
TRACE("dmFields=%s ", _DM_fields(devmode->dmFields));
if (devmode->dmFields & DM_BITSPERPEL)
TRACE("dmBitsPerPel=%u ", devmode->dmBitsPerPel);
if (devmode->dmFields & DM_PELSWIDTH)
TRACE("dmPelsWidth=%u ", devmode->dmPelsWidth);
if (devmode->dmFields & DM_PELSHEIGHT)
TRACE("dmPelsHeight=%u ", devmode->dmPelsHeight);
if (devmode->dmFields & DM_DISPLAYFREQUENCY)
TRACE("dmDisplayFrequency=%u ", devmode->dmDisplayFrequency);
if (devmode->dmFields & DM_POSITION)
TRACE("dmPosition=(%d,%d) ", devmode->u1.s2.dmPosition.x, devmode->u1.s2.dmPosition.y);
if (devmode->dmFields & DM_DISPLAYFLAGS)
TRACE("dmDisplayFlags=%#x ", devmode->u2.dmDisplayFlags);
if (devmode->dmFields & DM_DISPLAYORIENTATION)
TRACE("dmDisplayOrientation=%u ", devmode->u1.s2.dmDisplayOrientation);
TRACE("\n");
}
static BOOL is_detached_mode(const DEVMODEW *mode)
{
return mode->dmFields & DM_POSITION &&
mode->dmFields & DM_PELSWIDTH &&
mode->dmFields & DM_PELSHEIGHT &&
mode->dmPelsWidth == 0 &&
mode->dmPelsHeight == 0;
}
/***********************************************************************
* ChangeDisplaySettingsExW (USER32.@)
*/
LONG WINAPI ChangeDisplaySettingsExW( LPCWSTR devname, LPDEVMODEW devmode, HWND hwnd,
DWORD flags, LPVOID lparam )
{
WCHAR primary_adapter[CCHDEVICENAME];
BOOL def_mode = TRUE;
DEVMODEW dm;
LONG ret;
TRACE("%s %p %p %#x %p\n", debugstr_w(devname), devmode, hwnd, flags, lparam);
TRACE("flags=%s\n", _CDS_flags(flags));
if (!devname && !devmode)
{
ret = USER_Driver->pChangeDisplaySettingsEx(NULL, NULL, hwnd, flags, lparam);
if (ret != DISP_CHANGE_SUCCESSFUL)
ERR("Restoring all displays to their registry settings returned %d.\n", ret);
return ret;
}
if (!devname && devmode)
{
if (!get_primary_adapter(primary_adapter))
return DISP_CHANGE_FAILED;
devname = primary_adapter;
}
if (!is_valid_adapter_name(devname))
{
ERR("Invalid device name %s.\n", wine_dbgstr_w(devname));
return DISP_CHANGE_BADPARAM;
}
if (devmode)
{
trace_devmode(devmode);
if (devmode->dmSize < FIELD_OFFSET(DEVMODEW, dmICMMethod))
return DISP_CHANGE_BADMODE;
if (is_detached_mode(devmode) ||
((devmode->dmFields & DM_BITSPERPEL) && devmode->dmBitsPerPel) ||
((devmode->dmFields & DM_PELSWIDTH) && devmode->dmPelsWidth) ||
((devmode->dmFields & DM_PELSHEIGHT) && devmode->dmPelsHeight) ||
((devmode->dmFields & DM_DISPLAYFREQUENCY) && devmode->dmDisplayFrequency))
def_mode = FALSE;
}
if (def_mode)
{
memset(&dm, 0, sizeof(dm));
dm.dmSize = sizeof(dm);
if (!EnumDisplaySettingsExW(devname, ENUM_REGISTRY_SETTINGS, &dm, 0))
{
ERR("Default mode not found!\n");
return DISP_CHANGE_BADMODE;
}
TRACE("Return to original display mode\n");
devmode = &dm;
}
if ((devmode->dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != (DM_PELSWIDTH | DM_PELSHEIGHT))
{
WARN("devmode doesn't specify the resolution: %#x\n", devmode->dmFields);
return DISP_CHANGE_BADMODE;
}
if (!is_detached_mode(devmode) && (!devmode->dmPelsWidth || !devmode->dmPelsHeight))
{
memset(&dm, 0, sizeof(dm));
dm.dmSize = sizeof(dm);
if (!EnumDisplaySettingsExW(devname, ENUM_CURRENT_SETTINGS, &dm, 0))
{
ERR("Current mode not found!\n");
return DISP_CHANGE_BADMODE;
}
if (!devmode->dmPelsWidth)
devmode->dmPelsWidth = dm.dmPelsWidth;
if (!devmode->dmPelsHeight)
devmode->dmPelsHeight = dm.dmPelsHeight;
}
ret = USER_Driver->pChangeDisplaySettingsEx(devname, devmode, hwnd, flags, lparam);
if (ret != DISP_CHANGE_SUCCESSFUL)
ERR("Changing %s display settings returned %d.\n", wine_dbgstr_w(devname), ret);
return ret;
}
/***********************************************************************
* EnumDisplaySettingsW (USER32.@)
*
* RETURNS
* TRUE if nth setting exists found (described in the LPDEVMODEW struct)
* FALSE if we do not have the nth setting
*/
BOOL WINAPI EnumDisplaySettingsW( LPCWSTR name, DWORD n, LPDEVMODEW devmode )
{
return EnumDisplaySettingsExW(name, n, devmode, 0);
}
/***********************************************************************
* EnumDisplaySettingsA (USER32.@)
*/
BOOL WINAPI EnumDisplaySettingsA(LPCSTR name,DWORD n,LPDEVMODEA devmode)
{
return EnumDisplaySettingsExA(name, n, devmode, 0);
}
/***********************************************************************
* EnumDisplaySettingsExA (USER32.@)
*/
BOOL WINAPI EnumDisplaySettingsExA(LPCSTR lpszDeviceName, DWORD iModeNum,
LPDEVMODEA lpDevMode, DWORD dwFlags)
{
DEVMODEW devmodeW;
BOOL ret;
UNICODE_STRING nameW;
if (lpszDeviceName) RtlCreateUnicodeStringFromAsciiz(&nameW, lpszDeviceName);
else nameW.Buffer = NULL;
memset(&devmodeW, 0, sizeof(devmodeW));
devmodeW.dmSize = sizeof(devmodeW);
ret = EnumDisplaySettingsExW(nameW.Buffer,iModeNum,&devmodeW,dwFlags);
if (ret)
{
lpDevMode->dmSize = FIELD_OFFSET(DEVMODEA, dmICMMethod);
lpDevMode->dmSpecVersion = devmodeW.dmSpecVersion;
lpDevMode->dmDriverVersion = devmodeW.dmDriverVersion;
WideCharToMultiByte(CP_ACP, 0, devmodeW.dmDeviceName, -1,
(LPSTR)lpDevMode->dmDeviceName, CCHDEVICENAME, NULL, NULL);
lpDevMode->dmDriverExtra = 0; /* FIXME */
lpDevMode->dmBitsPerPel = devmodeW.dmBitsPerPel;
lpDevMode->dmPelsHeight = devmodeW.dmPelsHeight;
lpDevMode->dmPelsWidth = devmodeW.dmPelsWidth;
lpDevMode->u2.dmDisplayFlags = devmodeW.u2.dmDisplayFlags;
lpDevMode->dmDisplayFrequency = devmodeW.dmDisplayFrequency;
lpDevMode->dmFields = devmodeW.dmFields;
lpDevMode->u1.s2.dmPosition.x = devmodeW.u1.s2.dmPosition.x;
lpDevMode->u1.s2.dmPosition.y = devmodeW.u1.s2.dmPosition.y;
lpDevMode->u1.s2.dmDisplayOrientation = devmodeW.u1.s2.dmDisplayOrientation;
lpDevMode->u1.s2.dmDisplayFixedOutput = devmodeW.u1.s2.dmDisplayFixedOutput;
}
if (lpszDeviceName) RtlFreeUnicodeString(&nameW);
return ret;
}
/***********************************************************************
* EnumDisplaySettingsExW (USER32.@)
*/
BOOL WINAPI EnumDisplaySettingsExW(LPCWSTR lpszDeviceName, DWORD iModeNum,
LPDEVMODEW lpDevMode, DWORD dwFlags)
{
WCHAR primary_adapter[CCHDEVICENAME];
BOOL ret;
TRACE("%s %#x %p %#x\n", wine_dbgstr_w(lpszDeviceName), iModeNum, lpDevMode, dwFlags);
if (!lpszDeviceName)
{
if (!get_primary_adapter(primary_adapter))
return FALSE;
lpszDeviceName = primary_adapter;
}
if (!is_valid_adapter_name(lpszDeviceName))
{
ERR("Invalid device name %s.\n", wine_dbgstr_w(lpszDeviceName));
return FALSE;
}
ret = USER_Driver->pEnumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, dwFlags);
if (ret)
TRACE("device:%s mode index:%#x position:(%d,%d) resolution:%ux%u frequency:%uHz "
"depth:%ubits orientation:%#x.\n", wine_dbgstr_w(lpszDeviceName), iModeNum,
lpDevMode->u1.s2.dmPosition.x, lpDevMode->u1.s2.dmPosition.y, lpDevMode->dmPelsWidth,
lpDevMode->dmPelsHeight, lpDevMode->dmDisplayFrequency, lpDevMode->dmBitsPerPel,
lpDevMode->u1.s2.dmDisplayOrientation);
else
WARN("Failed to query %s display settings.\n", wine_dbgstr_w(lpszDeviceName));
return ret;
}
/**********************************************************************
* get_monitor_dpi
*/
UINT get_monitor_dpi( HMONITOR monitor )
{
/* FIXME: use the monitor DPI instead */
return system_dpi;
}
/**********************************************************************
* get_win_monitor_dpi
*/
UINT get_win_monitor_dpi( HWND hwnd )
{
/* FIXME: use the monitor DPI instead */
return system_dpi;
}
/**********************************************************************
* get_thread_dpi
*/
UINT get_thread_dpi(void)
{
switch (GetAwarenessFromDpiAwarenessContext( GetThreadDpiAwarenessContext() ))
{
case DPI_AWARENESS_UNAWARE: return USER_DEFAULT_SCREEN_DPI;
case DPI_AWARENESS_SYSTEM_AWARE: return system_dpi;
default: return 0; /* no scaling */
}
}
/**********************************************************************
* map_dpi_point
*/
POINT map_dpi_point( POINT pt, UINT dpi_from, UINT dpi_to )
{
if (dpi_from && dpi_to && dpi_from != dpi_to)
{
pt.x = MulDiv( pt.x, dpi_to, dpi_from );
pt.y = MulDiv( pt.y, dpi_to, dpi_from );
}
return pt;
}
/**********************************************************************
* point_win_to_phys_dpi
*/
POINT point_win_to_phys_dpi( HWND hwnd, POINT pt )
{
return map_dpi_point( pt, GetDpiForWindow( hwnd ), get_win_monitor_dpi( hwnd ) );
}
/**********************************************************************
* point_phys_to_win_dpi
*/
POINT point_phys_to_win_dpi( HWND hwnd, POINT pt )
{
return map_dpi_point( pt, get_win_monitor_dpi( hwnd ), GetDpiForWindow( hwnd ));
}
/**********************************************************************
* point_win_to_thread_dpi
*/
POINT point_win_to_thread_dpi( HWND hwnd, POINT pt )
{
UINT dpi = get_thread_dpi();
if (!dpi) dpi = get_win_monitor_dpi( hwnd );
return map_dpi_point( pt, GetDpiForWindow( hwnd ), dpi );
}
/**********************************************************************
* point_thread_to_win_dpi
*/
POINT point_thread_to_win_dpi( HWND hwnd, POINT pt )
{
UINT dpi = get_thread_dpi();
if (!dpi) dpi = get_win_monitor_dpi( hwnd );
return map_dpi_point( pt, dpi, GetDpiForWindow( hwnd ));
}
/**********************************************************************
* map_dpi_rect
*/
RECT map_dpi_rect( RECT rect, UINT dpi_from, UINT dpi_to )
{
if (dpi_from && dpi_to && dpi_from != dpi_to)
{
rect.left = MulDiv( rect.left, dpi_to, dpi_from );
rect.top = MulDiv( rect.top, dpi_to, dpi_from );
rect.right = MulDiv( rect.right, dpi_to, dpi_from );
rect.bottom = MulDiv( rect.bottom, dpi_to, dpi_from );
}
return rect;
}
/**********************************************************************
* rect_win_to_thread_dpi
*/
RECT rect_win_to_thread_dpi( HWND hwnd, RECT rect )
{
UINT dpi = get_thread_dpi();
if (!dpi) dpi = get_win_monitor_dpi( hwnd );
return map_dpi_rect( rect, GetDpiForWindow( hwnd ), dpi );
}
/**********************************************************************
* rect_thread_to_win_dpi
*/
RECT rect_thread_to_win_dpi( HWND hwnd, RECT rect )
{
UINT dpi = get_thread_dpi();
if (!dpi) dpi = get_win_monitor_dpi( hwnd );
return map_dpi_rect( rect, dpi, GetDpiForWindow( hwnd ) );
}
/**********************************************************************
* SetProcessDpiAwarenessContext (USER32.@)
*/
BOOL WINAPI SetProcessDpiAwarenessContext( DPI_AWARENESS_CONTEXT context )
{
DPI_AWARENESS val = GetAwarenessFromDpiAwarenessContext( context );
if (val == DPI_AWARENESS_INVALID)
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
val |= 0x10; /* avoid 0 value */
if (InterlockedCompareExchange( &dpi_awareness, val, 0 ))
{
SetLastError( ERROR_ACCESS_DENIED );
return FALSE;
}
TRACE( "set to %p\n", context );
return TRUE;
}
/**********************************************************************
* GetProcessDpiAwarenessInternal (USER32.@)
*/
BOOL WINAPI GetProcessDpiAwarenessInternal( HANDLE process, DPI_AWARENESS *awareness )
{
if (process && process != GetCurrentProcess())
{
WARN( "not supported on other process %p\n", process );
*awareness = DPI_AWARENESS_UNAWARE;
}
else *awareness = dpi_awareness & 3;
return TRUE;
}
/**********************************************************************
* SetProcessDpiAwarenessInternal (USER32.@)
*/
BOOL WINAPI SetProcessDpiAwarenessInternal( DPI_AWARENESS awareness )
{
static const DPI_AWARENESS_CONTEXT contexts[3] = { DPI_AWARENESS_CONTEXT_UNAWARE,
DPI_AWARENESS_CONTEXT_SYSTEM_AWARE,
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE };
if (awareness < DPI_AWARENESS_UNAWARE || awareness > DPI_AWARENESS_PER_MONITOR_AWARE)
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
return SetProcessDpiAwarenessContext( contexts[awareness] );
}
/***********************************************************************
* AreDpiAwarenessContextsEqual (USER32.@)
*/
BOOL WINAPI AreDpiAwarenessContextsEqual( DPI_AWARENESS_CONTEXT ctx1, DPI_AWARENESS_CONTEXT ctx2 )
{
DPI_AWARENESS aware1 = GetAwarenessFromDpiAwarenessContext( ctx1 );
DPI_AWARENESS aware2 = GetAwarenessFromDpiAwarenessContext( ctx2 );
return aware1 != DPI_AWARENESS_INVALID && aware1 == aware2;
}
/***********************************************************************
* GetAwarenessFromDpiAwarenessContext (USER32.@)
*/
DPI_AWARENESS WINAPI GetAwarenessFromDpiAwarenessContext( DPI_AWARENESS_CONTEXT context )
{
switch ((ULONG_PTR)context)
{
case 0x10:
case 0x11:
case 0x12:
case 0x80000010:
case 0x80000011:
case 0x80000012:
return (ULONG_PTR)context & 3;
case (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE:
case (ULONG_PTR)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE:
case (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE:
return ~(ULONG_PTR)context;
default:
return DPI_AWARENESS_INVALID;
}
}
/***********************************************************************
* IsValidDpiAwarenessContext (USER32.@)
*/
BOOL WINAPI IsValidDpiAwarenessContext( DPI_AWARENESS_CONTEXT context )
{
return GetAwarenessFromDpiAwarenessContext( context ) != DPI_AWARENESS_INVALID;
}
/***********************************************************************
* SetProcessDPIAware (USER32.@)
*/
BOOL WINAPI SetProcessDPIAware(void)
{
TRACE("\n");
InterlockedCompareExchange( &dpi_awareness, 0x11, 0 );
return TRUE;
}
/***********************************************************************
* IsProcessDPIAware (USER32.@)
*/
BOOL WINAPI IsProcessDPIAware(void)
{
return GetAwarenessFromDpiAwarenessContext( GetThreadDpiAwarenessContext() ) != DPI_AWARENESS_UNAWARE;
}
/**********************************************************************
* EnableNonClientDpiScaling (USER32.@)
*/
BOOL WINAPI EnableNonClientDpiScaling( HWND hwnd )
{
FIXME("(%p): stub\n", hwnd);
SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
return FALSE;
}
/***********************************************************************
* GetDpiForSystem (USER32.@)
*/
UINT WINAPI GetDpiForSystem(void)
{
if (!IsProcessDPIAware()) return USER_DEFAULT_SCREEN_DPI;
return system_dpi;
}
/***********************************************************************
* GetDpiForMonitorInternal (USER32.@)
*/
BOOL WINAPI GetDpiForMonitorInternal( HMONITOR monitor, UINT type, UINT *x, UINT *y )
{
if (type > 2)
{
SetLastError( ERROR_BAD_ARGUMENTS );
return FALSE;
}
if (!x || !y)
{
SetLastError( ERROR_INVALID_ADDRESS );
return FALSE;
}
switch (GetAwarenessFromDpiAwarenessContext( GetThreadDpiAwarenessContext() ))
{
case DPI_AWARENESS_UNAWARE: *x = *y = USER_DEFAULT_SCREEN_DPI; break;
case DPI_AWARENESS_SYSTEM_AWARE: *x = *y = system_dpi; break;
default: *x = *y = get_monitor_dpi( monitor ); break;
}
return TRUE;
}
/**********************************************************************
* GetThreadDpiAwarenessContext (USER32.@)
*/
DPI_AWARENESS_CONTEXT WINAPI GetThreadDpiAwarenessContext(void)
{
struct user_thread_info *info = get_user_thread_info();
if (info->dpi_awareness) return ULongToHandle( info->dpi_awareness );
if (dpi_awareness) return ULongToHandle( dpi_awareness );
return ULongToHandle( 0x10 | default_awareness );
}
/**********************************************************************
* SetThreadDpiAwarenessContext (USER32.@)
*/
DPI_AWARENESS_CONTEXT WINAPI SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT context )
{
struct user_thread_info *info = get_user_thread_info();
DPI_AWARENESS prev, val = GetAwarenessFromDpiAwarenessContext( context );
if (val == DPI_AWARENESS_INVALID)
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
if (!(prev = info->dpi_awareness))
{
prev = dpi_awareness;
if (!prev) prev = 0x10 | DPI_AWARENESS_UNAWARE;
prev |= 0x80000000; /* restore to process default */
}
if (((ULONG_PTR)context & ~(ULONG_PTR)0x13) == 0x80000000) info->dpi_awareness = 0;
else info->dpi_awareness = val | 0x10;
return ULongToHandle( prev );
}
/**********************************************************************
* LogicalToPhysicalPointForPerMonitorDPI (USER32.@)
*/
BOOL WINAPI LogicalToPhysicalPointForPerMonitorDPI( HWND hwnd, POINT *pt )
{
RECT rect;
if (!GetWindowRect( hwnd, &rect )) return FALSE;
if (pt->x < rect.left || pt->y < rect.top || pt->x > rect.right || pt->y > rect.bottom) return FALSE;
*pt = point_win_to_phys_dpi( hwnd, *pt );
return TRUE;
}
/**********************************************************************
* PhysicalToLogicalPointForPerMonitorDPI (USER32.@)
*/
BOOL WINAPI PhysicalToLogicalPointForPerMonitorDPI( HWND hwnd, POINT *pt )
{
DPI_AWARENESS_CONTEXT context;
RECT rect;
BOOL ret = FALSE;
context = SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
if (GetWindowRect( hwnd, &rect ) &&
pt->x >= rect.left && pt->y >= rect.top && pt->x <= rect.right && pt->y <= rect.bottom)
{
*pt = point_phys_to_win_dpi( hwnd, *pt );
ret = TRUE;
}
SetThreadDpiAwarenessContext( context );
return ret;
}
struct monitor_enum_info
{
RECT rect;
UINT max_area;
UINT min_distance;
HMONITOR primary;
HMONITOR nearest;
HMONITOR ret;
};
/* helper callback for MonitorFromRect */
static BOOL CALLBACK monitor_enum( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
{
struct monitor_enum_info *info = (struct monitor_enum_info *)lp;
RECT intersect;
if (IntersectRect( &intersect, rect, &info->rect ))
{
/* check for larger intersecting area */
UINT area = (intersect.right - intersect.left) * (intersect.bottom - intersect.top);
if (area > info->max_area)
{
info->max_area = area;
info->ret = monitor;
}
}
else if (!info->max_area) /* if not intersecting, check for min distance */
{
UINT distance;
UINT x, y;
if (info->rect.right <= rect->left) x = rect->left - info->rect.right;
else if (rect->right <= info->rect.left) x = info->rect.left - rect->right;
else x = 0;
if (info->rect.bottom <= rect->top) y = rect->top - info->rect.bottom;
else if (rect->bottom <= info->rect.top) y = info->rect.top - rect->bottom;
else y = 0;
distance = x * x + y * y;
if (distance < info->min_distance)
{
info->min_distance = distance;
info->nearest = monitor;
}
}
if (!info->primary)
{
MONITORINFO mon_info;
mon_info.cbSize = sizeof(mon_info);
GetMonitorInfoW( monitor, &mon_info );
if (mon_info.dwFlags & MONITORINFOF_PRIMARY) info->primary = monitor;
}
return TRUE;
}
/***********************************************************************
* MonitorFromRect (USER32.@)
*/
HMONITOR WINAPI MonitorFromRect( const RECT *rect, DWORD flags )
{
struct monitor_enum_info info;
info.rect = *rect;
info.max_area = 0;
info.min_distance = ~0u;
info.primary = 0;
info.nearest = 0;
info.ret = 0;
if (IsRectEmpty(&info.rect))
{
info.rect.right = info.rect.left + 1;
info.rect.bottom = info.rect.top + 1;
}
if (!EnumDisplayMonitors( 0, NULL, monitor_enum, (LPARAM)&info )) return 0;
if (!info.ret)
{
if (flags & MONITOR_DEFAULTTOPRIMARY) info.ret = info.primary;
else if (flags & MONITOR_DEFAULTTONEAREST) info.ret = info.nearest;
}
TRACE( "%s flags %x returning %p\n", wine_dbgstr_rect(rect), flags, info.ret );
return info.ret;
}
/***********************************************************************
* MonitorFromPoint (USER32.@)
*/
HMONITOR WINAPI MonitorFromPoint( POINT pt, DWORD flags )
{
RECT rect;
SetRect( &rect, pt.x, pt.y, pt.x + 1, pt.y + 1 );
return MonitorFromRect( &rect, flags );
}
/***********************************************************************
* MonitorFromWindow (USER32.@)
*/
HMONITOR WINAPI MonitorFromWindow(HWND hWnd, DWORD dwFlags)
{
RECT rect;
WINDOWPLACEMENT wp;
TRACE("(%p, 0x%08x)\n", hWnd, dwFlags);
wp.length = sizeof(wp);
if (IsIconic(hWnd) && GetWindowPlacement(hWnd, &wp))
return MonitorFromRect( &wp.rcNormalPosition, dwFlags );
if (GetWindowRect( hWnd, &rect ))
return MonitorFromRect( &rect, dwFlags );
if (!(dwFlags & (MONITOR_DEFAULTTOPRIMARY|MONITOR_DEFAULTTONEAREST))) return 0;
/* retrieve the primary */
SetRect( &rect, 0, 0, 1, 1 );
return MonitorFromRect( &rect, dwFlags );
}
/* Return FALSE on failure and TRUE on success */
static BOOL update_display_cache(void)
{
struct display_device device, *adapter, *adapter2, *monitor, *monitor2;
DWORD adapter_idx, monitor_idx;
struct list *monitor_list;
FILETIME filetime = {0};
HANDLE mutex = NULL;
BOOL ret = FALSE;
/* Update display cache from SetupAPI if it's outdated */
wait_graphics_driver_ready();
if (!video_key && RegOpenKeyW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", &video_key ))
return FALSE;
if (RegQueryInfoKeyW( video_key, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &filetime ))
return FALSE;
if (CompareFileTime( &filetime, &last_query_display_time ) < 1)
return TRUE;
mutex = get_display_device_init_mutex();
EnterCriticalSection( &display_section );
LIST_FOR_EACH_ENTRY_SAFE(adapter, adapter2, &adapters, struct display_device, entry)
{
LIST_FOR_EACH_ENTRY_SAFE(monitor, monitor2, &adapter->children, struct display_device, entry)
{
list_remove( &monitor->entry );
heap_free( monitor );
}
list_remove( &adapter->entry );
heap_free( adapter );
}
for (adapter_idx = 0; enum_display_device( NULL, adapter_idx, &device ); ++adapter_idx)
{
adapter = heap_alloc( sizeof(*adapter) );
if (!adapter)
goto fail;
memcpy( adapter, &device, sizeof(device) );
monitor_list = &adapter->children;
list_init( monitor_list );
list_add_tail( &adapters, &adapter->entry );
for (monitor_idx = 0; enum_display_device( adapter->device_name, monitor_idx, &device ); ++monitor_idx)
{
monitor = heap_alloc( sizeof(*monitor) );
if (!monitor)
goto fail;
memcpy( monitor, &device, sizeof(device) );
list_add_tail( monitor_list, &monitor->entry );
}
}
last_query_display_time = filetime;
ret = TRUE;
fail:
LeaveCriticalSection( &display_section );
release_display_device_init_mutex( mutex );
return ret;
}
/* Return FALSE on failure and TRUE on success */
static BOOL update_monitor_cache(void)
{
SP_DEVINFO_DATA device_data = {sizeof(device_data)};
HDEVINFO devinfo = INVALID_HANDLE_VALUE;
MONITORINFOEXW *monitor_array;
FILETIME filetime = {0};
DWORD device_count = 0;
HANDLE mutex = NULL;
DWORD state_flags;
BOOL ret = FALSE;
BOOL is_replica;
DWORD i = 0, j;
DWORD type;
/* Update monitor cache from SetupAPI if it's outdated */
if (!video_key && RegOpenKeyW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", &video_key ))
return FALSE;
if (RegQueryInfoKeyW( video_key, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &filetime ))
return FALSE;
if (CompareFileTime( &filetime, &last_query_monitors_time ) < 1)
return TRUE;
mutex = get_display_device_init_mutex();
EnterCriticalSection( &monitors_section );
devinfo = SetupDiGetClassDevsW( &GUID_DEVCLASS_MONITOR, L"DISPLAY", NULL, DIGCF_PRESENT );
while (SetupDiEnumDeviceInfo( devinfo, i++, &device_data ))
{
/* Inactive monitors don't get enumerated */
if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, &type,
(BYTE *)&state_flags, sizeof(DWORD), NULL, 0 ))
goto fail;
if (state_flags & DISPLAY_DEVICE_ACTIVE)
device_count++;
}
if (device_count && monitor_count < device_count)
{
monitor_array = heap_alloc( device_count * sizeof(*monitor_array) );
if (!monitor_array)
goto fail;
heap_free( monitors );
monitors = monitor_array;
}
for (i = 0, monitor_count = 0; SetupDiEnumDeviceInfo( devinfo, i, &device_data ); i++)
{
if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, &type,
(BYTE *)&state_flags, sizeof(DWORD), NULL, 0 ))
goto fail;
if (!(state_flags & DISPLAY_DEVICE_ACTIVE))
continue;
if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCMONITOR, &type,
(BYTE *)&monitors[monitor_count].rcMonitor, sizeof(RECT), NULL, 0 ))
goto fail;
/* Replicas in mirroring monitor sets don't get enumerated */
is_replica = FALSE;
for (j = 0; j < monitor_count; j++)
{
if (EqualRect(&monitors[j].rcMonitor, &monitors[monitor_count].rcMonitor))
{
is_replica = TRUE;
break;
}
}
if (is_replica)
continue;
if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCWORK, &type,
(BYTE *)&monitors[monitor_count].rcWork, sizeof(RECT), NULL, 0 ))
goto fail;
if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_ADAPTERNAME, &type,
(BYTE *)monitors[monitor_count].szDevice, CCHDEVICENAME * sizeof(WCHAR), NULL, 0))
goto fail;
monitors[monitor_count].dwFlags =
!wcscmp( L"\\\\.\\DISPLAY1", monitors[monitor_count].szDevice ) ? MONITORINFOF_PRIMARY : 0;
monitor_count++;
}
last_query_monitors_time = filetime;
ret = TRUE;
fail:
SetupDiDestroyDeviceInfoList( devinfo );
LeaveCriticalSection( &monitors_section );
release_display_device_init_mutex( mutex );
return ret;
}
BOOL CDECL nulldrv_GetMonitorInfo( HMONITOR handle, MONITORINFO *info )
{
UINT index = (UINT_PTR)handle - 1;
TRACE("(%p, %p)\n", handle, info);
/* Fallback to report one monitor */
if (handle == NULLDRV_DEFAULT_HMONITOR)
{
RECT default_rect = {0, 0, 1024, 768};
info->rcMonitor = default_rect;
info->rcWork = default_rect;
info->dwFlags = MONITORINFOF_PRIMARY;
if (info->cbSize >= sizeof(MONITORINFOEXW))
lstrcpyW( ((MONITORINFOEXW *)info)->szDevice, L"WinDisc" );
return TRUE;
}
if (!update_monitor_cache())
return FALSE;
EnterCriticalSection( &monitors_section );
if (index < monitor_count)
{
info->rcMonitor = monitors[index].rcMonitor;
info->rcWork = monitors[index].rcWork;
info->dwFlags = monitors[index].dwFlags;
if (info->cbSize >= sizeof(MONITORINFOEXW))
lstrcpyW( ((MONITORINFOEXW *)info)->szDevice, monitors[index].szDevice );
LeaveCriticalSection( &monitors_section );
return TRUE;
}
else
{
LeaveCriticalSection( &monitors_section );
SetLastError( ERROR_INVALID_MONITOR_HANDLE );
return FALSE;
}
}
/***********************************************************************
* GetMonitorInfoA (USER32.@)
*/
BOOL WINAPI GetMonitorInfoA( HMONITOR monitor, LPMONITORINFO info )
{
MONITORINFOEXW miW;
BOOL ret;
if (info->cbSize == sizeof(MONITORINFO)) return GetMonitorInfoW( monitor, info );
if (info->cbSize != sizeof(MONITORINFOEXA)) return FALSE;
miW.cbSize = sizeof(miW);
ret = GetMonitorInfoW( monitor, (MONITORINFO *)&miW );
if (ret)
{
MONITORINFOEXA *miA = (MONITORINFOEXA *)info;
miA->rcMonitor = miW.rcMonitor;
miA->rcWork = miW.rcWork;
miA->dwFlags = miW.dwFlags;
WideCharToMultiByte(CP_ACP, 0, miW.szDevice, -1, miA->szDevice, sizeof(miA->szDevice), NULL, NULL);
}
return ret;
}
/***********************************************************************
* GetMonitorInfoW (USER32.@)
*/
BOOL WINAPI GetMonitorInfoW( HMONITOR monitor, LPMONITORINFO info )
{
BOOL ret;
UINT dpi_from, dpi_to;
if (info->cbSize != sizeof(MONITORINFOEXW) && info->cbSize != sizeof(MONITORINFO)) return FALSE;
ret = USER_Driver->pGetMonitorInfo( monitor, info );
if (ret)
{
if ((dpi_to = get_thread_dpi()))
{
dpi_from = get_monitor_dpi( monitor );
info->rcMonitor = map_dpi_rect( info->rcMonitor, dpi_from, dpi_to );
info->rcWork = map_dpi_rect( info->rcWork, dpi_from, dpi_to );
}
TRACE( "flags %04x, monitor %s, work %s\n", info->dwFlags,
wine_dbgstr_rect(&info->rcMonitor), wine_dbgstr_rect(&info->rcWork));
}
return ret;
}
struct enum_mon_data
{
MONITORENUMPROC proc;
LPARAM lparam;
HDC hdc;
POINT origin;
RECT limit;
};
#ifdef __i386__
/* Some apps pass a non-stdcall callback to EnumDisplayMonitors,
* so we need a small assembly wrapper to call it.
* MJ's Help Diagnostic expects that %ecx contains the address to the rect.
*/
extern BOOL enum_mon_callback_wrapper( HMONITOR monitor, LPRECT rect, struct enum_mon_data *data );
__ASM_GLOBAL_FUNC( enum_mon_callback_wrapper,
"pushl %ebp\n\t"
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
__ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
"movl %esp,%ebp\n\t"
__ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
"subl $8,%esp\n\t"
"movl 16(%ebp),%eax\n\t" /* data */
"movl 12(%ebp),%ecx\n\t" /* rect */
"pushl 4(%eax)\n\t" /* data->lparam */
"pushl %ecx\n\t" /* rect */
"pushl 8(%eax)\n\t" /* data->hdc */
"pushl 8(%ebp)\n\t" /* monitor */
"call *(%eax)\n\t" /* data->proc */
"leave\n\t"
__ASM_CFI(".cfi_def_cfa %esp,4\n\t")
__ASM_CFI(".cfi_same_value %ebp\n\t")
"ret" )
#endif /* __i386__ */
static BOOL CALLBACK enum_mon_callback( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
{
struct enum_mon_data *data = (struct enum_mon_data *)lp;
RECT monrect = map_dpi_rect( *rect, get_monitor_dpi( monitor ), get_thread_dpi() );
OffsetRect( &monrect, -data->origin.x, -data->origin.y );
if (!IntersectRect( &monrect, &monrect, &data->limit )) return TRUE;
#ifdef __i386__
return enum_mon_callback_wrapper( monitor, &monrect, data );
#else
return data->proc( monitor, data->hdc, &monrect, data->lparam );
#endif
}
BOOL CDECL nulldrv_EnumDisplayMonitors( HDC hdc, RECT *rect, MONITORENUMPROC proc, LPARAM lp )
{
BOOL is_winstation_visible = FALSE;
USEROBJECTFLAGS flags;
HWINSTA winstation;
RECT monitor_rect;
DWORD i = 0;
TRACE("(%p, %p, %p, 0x%lx)\n", hdc, rect, proc, lp);
/* Report physical monitor information only if window station has visible display surfaces */
winstation = NtUserGetProcessWindowStation();
if (NtUserGetObjectInformation( winstation, UOI_FLAGS, &flags, sizeof(flags), NULL ))
is_winstation_visible = flags.dwFlags & WSF_VISIBLE;
if (is_winstation_visible && update_monitor_cache())
{
while (TRUE)
{
EnterCriticalSection( &monitors_section );
if (i >= monitor_count)
{
LeaveCriticalSection( &monitors_section );
return TRUE;
}
monitor_rect = monitors[i].rcMonitor;
LeaveCriticalSection( &monitors_section );
if (!proc( (HMONITOR)(UINT_PTR)(i + 1), hdc, &monitor_rect, lp ))
return FALSE;
++i;
}
}
/* Fallback to report one monitor if using SetupAPI failed */
SetRect( &monitor_rect, 0, 0, 1024, 768 );
if (!proc( NULLDRV_DEFAULT_HMONITOR, hdc, &monitor_rect, lp ))
return FALSE;
return TRUE;
}
/***********************************************************************
* EnumDisplayMonitors (USER32.@)
*/
BOOL WINAPI EnumDisplayMonitors( HDC hdc, LPRECT rect, MONITORENUMPROC proc, LPARAM lp )
{
struct enum_mon_data data;
data.proc = proc;
data.lparam = lp;
data.hdc = hdc;
if (hdc)
{
if (!GetDCOrgEx( hdc, &data.origin )) return FALSE;
if (GetClipBox( hdc, &data.limit ) == ERROR) return FALSE;
}
else
{
data.origin.x = data.origin.y = 0;
data.limit.left = data.limit.top = INT_MIN;
data.limit.right = data.limit.bottom = INT_MAX;
}
if (rect && !IntersectRect( &data.limit, &data.limit, rect )) return TRUE;
return USER_Driver->pEnumDisplayMonitors( 0, NULL, enum_mon_callback, (LPARAM)&data );
}
/***********************************************************************
* EnumDisplayDevicesA (USER32.@)
*/
BOOL WINAPI EnumDisplayDevicesA( LPCSTR device, DWORD index, DISPLAY_DEVICEA *info, DWORD flags )
{
UNICODE_STRING deviceW;
DISPLAY_DEVICEW ddW;
BOOL ret;
if (device)
RtlCreateUnicodeStringFromAsciiz( &deviceW, device );
else
deviceW.Buffer = NULL;
ddW.cb = sizeof(ddW);
ret = EnumDisplayDevicesW( deviceW.Buffer, index, &ddW, flags );
RtlFreeUnicodeString( &deviceW );
if (!ret)
return ret;
WideCharToMultiByte( CP_ACP, 0, ddW.DeviceName, -1, info->DeviceName, sizeof(info->DeviceName), NULL, NULL );
WideCharToMultiByte( CP_ACP, 0, ddW.DeviceString, -1, info->DeviceString, sizeof(info->DeviceString), NULL, NULL );
info->StateFlags = ddW.StateFlags;
if (info->cb >= offsetof(DISPLAY_DEVICEA, DeviceID) + sizeof(info->DeviceID))
WideCharToMultiByte( CP_ACP, 0, ddW.DeviceID, -1, info->DeviceID, sizeof(info->DeviceID), NULL, NULL );
if (info->cb >= offsetof(DISPLAY_DEVICEA, DeviceKey) + sizeof(info->DeviceKey))
WideCharToMultiByte( CP_ACP, 0, ddW.DeviceKey, -1, info->DeviceKey, sizeof(info->DeviceKey), NULL, NULL );
return TRUE;
}
/***********************************************************************
* EnumDisplayDevicesW (USER32.@)
*/
BOOL WINAPI EnumDisplayDevicesW( LPCWSTR device, DWORD index, DISPLAY_DEVICEW *info, DWORD flags )
{
struct display_device *adapter, *monitor, *found = NULL;
DWORD device_idx = 0;
TRACE("%s %u %p %#x\n", debugstr_w( device ), index, info, flags);
if (!update_display_cache())
return FALSE;
EnterCriticalSection( &display_section );
/* Enumerate adapters */
if (!device)
{
LIST_FOR_EACH_ENTRY(adapter, &adapters, struct display_device, entry)
{
if (index == device_idx++)
{
found = adapter;
break;
}
}
}
/* Enumerate monitors */
else
{
LIST_FOR_EACH_ENTRY(adapter, &adapters, struct display_device, entry)
{
if (!lstrcmpiW( device, adapter->device_name ))
{
found = adapter;
break;
}
}
if (found)
{
found = NULL;
LIST_FOR_EACH_ENTRY(monitor, &adapter->children, struct display_device, entry)
{
if (index == device_idx++)
{
found = monitor;
break;
}
}
}
}
if (!found)
{
LeaveCriticalSection( &display_section );
return FALSE;
}
if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceName) + sizeof(info->DeviceName))
lstrcpyW( info->DeviceName, found->device_name );
if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceString) + sizeof(info->DeviceString))
lstrcpyW( info->DeviceString, found->device_string );
if (info->cb >= offsetof(DISPLAY_DEVICEW, StateFlags) + sizeof(info->StateFlags))
info->StateFlags = found->state_flags;
if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->DeviceID))
lstrcpyW( info->DeviceID, (flags & EDD_GET_DEVICE_INTERFACE_NAME) ? found->interface_name : found->device_id );
if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(info->DeviceKey))
lstrcpyW( info->DeviceKey, found->device_key );
LeaveCriticalSection( &display_section );
return TRUE;
}
/* Call this function with the display_device_init mutex held */
static BOOL enum_display_device( WCHAR *device, DWORD index, struct display_device *info )
{
SP_DEVINFO_DATA device_data = {sizeof(device_data)};
HDEVINFO set = INVALID_HANDLE_VALUE;
WCHAR key_nameW[MAX_PATH];
WCHAR instanceW[MAX_PATH];
WCHAR bufferW[1024];
LONG adapter_index;
WCHAR *next_charW;
DWORD size;
DWORD type;
HKEY hkey;
BOOL ret = FALSE;
/* Find adapter */
if (!device)
{
swprintf( key_nameW, ARRAY_SIZE(key_nameW), L"\\Device\\Video%d", index );
size = sizeof(bufferW);
if (RegGetValueW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", key_nameW, RRF_RT_REG_SZ, NULL, bufferW, &size ))
goto done;
/* DeviceKey */
lstrcpyW( info->device_key, bufferW );
/* DeviceName */
swprintf( info->device_name, ARRAY_SIZE(info->device_name), L"\\\\.\\DISPLAY%d", index + 1 );
/* Strip \Registry\Machine\ */
lstrcpyW( key_nameW, bufferW + 18 );
/* DeviceString */
size = sizeof(info->device_string);
if (RegGetValueW( HKEY_LOCAL_MACHINE, key_nameW, L"DriverDesc", RRF_RT_REG_SZ, NULL,
info->device_string, &size ))
goto done;
/* StateFlags */
size = sizeof(info->state_flags);
if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, L"StateFlags", RRF_RT_REG_DWORD, NULL,
&info->state_flags, &size ))
goto done;
/* Interface name */
info->interface_name[0] = 0;
/* DeviceID */
size = sizeof(bufferW);
if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, L"GPUID", RRF_RT_REG_SZ | RRF_ZEROONFAILURE, NULL,
bufferW, &size ))
goto done;
set = SetupDiCreateDeviceInfoList( &GUID_DEVCLASS_DISPLAY, NULL );
if (!SetupDiOpenDeviceInfoW( set, bufferW, NULL, 0, &device_data )
|| !SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_HARDWAREID, NULL, (BYTE *)bufferW,
sizeof(bufferW), NULL ))
goto done;
lstrcpyW( info->device_id, bufferW );
}
/* Find monitor */
else
{
/* Check adapter name */
if (wcsnicmp( device, L"\\\\.\\DISPLAY", lstrlenW(L"\\\\.\\DISPLAY") ))
goto done;
adapter_index = wcstol( device + lstrlenW(L"\\\\.\\DISPLAY"), NULL, 10 );
swprintf( key_nameW, ARRAY_SIZE(key_nameW), L"\\Device\\Video%d", adapter_index - 1 );
size = sizeof(bufferW);
if (RegGetValueW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", key_nameW, RRF_RT_REG_SZ, NULL, bufferW, &size ))
goto done;
/* DeviceName */
swprintf( info->device_name, ARRAY_SIZE(info->device_name), L"\\\\.\\DISPLAY%d\\Monitor%d", adapter_index, index );
/* Get monitor instance */
/* Strip \Registry\Machine\ first */
lstrcpyW( key_nameW, bufferW + 18 );
swprintf( bufferW, ARRAY_SIZE(bufferW), L"MonitorID%d", index );
size = sizeof(instanceW);
if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, bufferW, RRF_RT_REG_SZ, NULL, instanceW, &size ))
goto done;
set = SetupDiCreateDeviceInfoList( &GUID_DEVCLASS_MONITOR, NULL );
if (!SetupDiOpenDeviceInfoW( set, instanceW, NULL, 0, &device_data ))
goto done;
/* StateFlags */
if (!SetupDiGetDevicePropertyW( set, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, &type,
(BYTE *)&info->state_flags, sizeof(info->state_flags), NULL, 0 ))
goto done;
/* DeviceString */
if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_DEVICEDESC, NULL,
(BYTE *)info->device_string,
sizeof(info->device_string), NULL ))
goto done;
/* DeviceKey */
if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW,
sizeof(bufferW), NULL ))
goto done;
lstrcpyW( info->device_key, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\" );
lstrcatW( info->device_key, bufferW );
/* Interface name */
lstrcpyW( info->interface_name, L"\\\\\?\\" );
lstrcatW( info->interface_name, instanceW );
lstrcatW( info->interface_name, L"#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}" );
/* Replace '\\' with '#' after prefix */
for (next_charW = info->interface_name + lstrlenW( L"\\\\\?\\" ); *next_charW; next_charW++)
{
if (*next_charW == '\\')
*next_charW = '#';
}
/* DeviceID */
if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_HARDWAREID, NULL, (BYTE *)bufferW,
sizeof(bufferW), NULL ))
goto done;
lstrcpyW( info->device_id, bufferW );
lstrcatW( info->device_id, L"\\" );
if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW,
sizeof(bufferW), NULL ))
goto done;
lstrcatW( info->device_id, bufferW );
}
ret = TRUE;
done:
SetupDiDestroyDeviceInfoList( set );
if (ret)
return ret;
/* Fallback to report at least one adapter and monitor, if user driver didn't initialize display device registry */
if (index)
return FALSE;
/* If user driver did initialize the registry, then exit */
if (!RegOpenKeyW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", &hkey ))
{
RegCloseKey( hkey );
return FALSE;
}
WARN("Reporting fallback display devices\n");
/* Adapter */
if (!device)
{
lstrcpyW( info->device_name, L"\\\\.\\DISPLAY1" );
lstrcpyW( info->device_string, L"Wine Adapter" );
info->state_flags = DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_PRIMARY_DEVICE | DISPLAY_DEVICE_VGA_COMPATIBLE;
info->interface_name[0] = 0;
lstrcpyW( info->device_id, L"PCI\\VEN_0000&DEV_0000&SUBSYS_00000000&REV_00" );
info->device_key[0] = 0;
}
/* Monitor */
else
{
if (lstrcmpiW( L"\\\\.\\DISPLAY1", device ))
return FALSE;
lstrcpyW( info->device_name, L"\\\\.\\DISPLAY1\\Monitor0" );
lstrcpyW( info->device_string, L"Generic Non-PnP Monitor" );
info->state_flags = DISPLAY_DEVICE_ACTIVE | DISPLAY_DEVICE_ATTACHED;
lstrcpyW( info->interface_name, L"\\\\\?\\DISPLAY#Default_Monitor#4&17f0ff54&0&UID0#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}" );
lstrcpyW( info->device_id, L"MONITOR\\Default_Monitor\\{4d36e96e-e325-11ce-bfc1-08002be10318}\\0000" );
info->device_key[0] = 0;
}
return TRUE;
}
/**********************************************************************
* GetAutoRotationState [USER32.@]
*/
BOOL WINAPI GetAutoRotationState( AR_STATE *state )
{
TRACE("(%p)\n", state);
if (!state)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
*state = AR_NOSENSOR;
return TRUE;
}
/**********************************************************************
* GetDisplayAutoRotationPreferences [USER32.@]
*/
BOOL WINAPI GetDisplayAutoRotationPreferences( ORIENTATION_PREFERENCE *orientation )
{
FIXME("(%p): stub\n", orientation);
*orientation = ORIENTATION_PREFERENCE_NONE;
return TRUE;
}
/* physical<->logical mapping functions from win8 that are nops in later versions */
/***********************************************************************
* GetPhysicalCursorPos (USER32.@)
*/
BOOL WINAPI GetPhysicalCursorPos( POINT *point )
{
return GetCursorPos( point );
}
/***********************************************************************
* SetPhysicalCursorPos (USER32.@)
*/
BOOL WINAPI SetPhysicalCursorPos( INT x, INT y )
{
return SetCursorPos( x, y );
}
/***********************************************************************
* WindowFromPhysicalPoint (USER32.@)
*/
HWND WINAPI WindowFromPhysicalPoint( POINT pt )
{
return WindowFromPoint( pt );
}
/***********************************************************************
* LogicalToPhysicalPoint (USER32.@)
*/
BOOL WINAPI LogicalToPhysicalPoint( HWND hwnd, POINT *point )
{
return TRUE;
}
/***********************************************************************
* PhysicalToLogicalPoint (USER32.@)
*/
BOOL WINAPI PhysicalToLogicalPoint( HWND hwnd, POINT *point )
{
return TRUE;
}
/**********************************************************************
* GetDisplayConfigBufferSizes (USER32.@)
*/
LONG WINAPI GetDisplayConfigBufferSizes(UINT32 flags, UINT32 *num_path_info, UINT32 *num_mode_info)
{
LONG ret = ERROR_GEN_FAILURE;
HANDLE mutex;
HDEVINFO devinfo;
SP_DEVINFO_DATA device_data = {sizeof(device_data)};
DWORD monitor_index = 0, state_flags, type;
FIXME("(0x%x %p %p): semi-stub\n", flags, num_path_info, num_mode_info);
if (!num_path_info || !num_mode_info)
return ERROR_INVALID_PARAMETER;
*num_path_info = 0;
if (flags != QDC_ALL_PATHS &&
flags != QDC_ONLY_ACTIVE_PATHS &&
flags != QDC_DATABASE_CURRENT)
return ERROR_INVALID_PARAMETER;
if (flags != QDC_ONLY_ACTIVE_PATHS)
FIXME("only returning active paths\n");
wait_graphics_driver_ready();
mutex = get_display_device_init_mutex();
/* Iterate through "targets"/monitors.
* Each target corresponds to a path, and each path references a source and a target mode.
*/
devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, L"DISPLAY", NULL, DIGCF_PRESENT);
if (devinfo == INVALID_HANDLE_VALUE)
goto done;
while (SetupDiEnumDeviceInfo(devinfo, monitor_index++, &device_data))
{
/* Only count active monitors */
if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS,
&type, (BYTE *)&state_flags, sizeof(state_flags), NULL, 0))
goto done;
if (state_flags & DISPLAY_DEVICE_ACTIVE)
(*num_path_info)++;
}
*num_mode_info = *num_path_info * 2;
ret = ERROR_SUCCESS;
TRACE("returning %u path(s) %u mode(s)\n", *num_path_info, *num_mode_info);
done:
SetupDiDestroyDeviceInfoList(devinfo);
release_display_device_init_mutex(mutex);
return ret;
}
static DISPLAYCONFIG_ROTATION get_dc_rotation(const DEVMODEW *devmode)
{
if (devmode->dmFields & DM_DISPLAYORIENTATION)
return devmode->u1.s2.dmDisplayOrientation + 1;
else
return DISPLAYCONFIG_ROTATION_IDENTITY;
}
static DISPLAYCONFIG_SCANLINE_ORDERING get_dc_scanline_ordering(const DEVMODEW *devmode)
{
if (!(devmode->dmFields & DM_DISPLAYFLAGS))
return DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED;
else if (devmode->u2.dmDisplayFlags & DM_INTERLACED)
return DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED;
else
return DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE;
}
static DISPLAYCONFIG_PIXELFORMAT get_dc_pixelformat(DWORD dmBitsPerPel)
{
if ((dmBitsPerPel == 8) || (dmBitsPerPel == 16) ||
(dmBitsPerPel == 24) || (dmBitsPerPel == 32))
return dmBitsPerPel / 8;
else
return DISPLAYCONFIG_PIXELFORMAT_NONGDI;
}
static void set_mode_target_info(DISPLAYCONFIG_MODE_INFO *info, const LUID *gpu_luid, UINT32 target_id,
UINT32 flags, const DEVMODEW *devmode)
{
DISPLAYCONFIG_TARGET_MODE *mode = &(info->u.targetMode);
info->infoType = DISPLAYCONFIG_MODE_INFO_TYPE_TARGET;
info->adapterId = *gpu_luid;
info->id = target_id;
/* FIXME: Populate pixelRate/hSyncFreq/totalSize with real data */
mode->targetVideoSignalInfo.pixelRate = devmode->dmDisplayFrequency * devmode->dmPelsWidth * devmode->dmPelsHeight;
mode->targetVideoSignalInfo.hSyncFreq.Numerator = devmode->dmDisplayFrequency * devmode->dmPelsWidth;
mode->targetVideoSignalInfo.hSyncFreq.Denominator = 1;
mode->targetVideoSignalInfo.vSyncFreq.Numerator = devmode->dmDisplayFrequency;
mode->targetVideoSignalInfo.vSyncFreq.Denominator = 1;
mode->targetVideoSignalInfo.activeSize.cx = devmode->dmPelsWidth;
mode->targetVideoSignalInfo.activeSize.cy = devmode->dmPelsHeight;
if (flags & QDC_DATABASE_CURRENT)
{
mode->targetVideoSignalInfo.totalSize.cx = 0;
mode->targetVideoSignalInfo.totalSize.cy = 0;
}
else
{
mode->targetVideoSignalInfo.totalSize.cx = devmode->dmPelsWidth;
mode->targetVideoSignalInfo.totalSize.cy = devmode->dmPelsHeight;
}
mode->targetVideoSignalInfo.u.videoStandard = D3DKMDT_VSS_OTHER;
mode->targetVideoSignalInfo.scanLineOrdering = get_dc_scanline_ordering(devmode);
}
static void set_path_target_info(DISPLAYCONFIG_PATH_TARGET_INFO *info, const LUID *gpu_luid,
UINT32 target_id, UINT32 mode_index, const DEVMODEW *devmode)
{
info->adapterId = *gpu_luid;
info->id = target_id;
info->u.modeInfoIdx = mode_index;
info->outputTechnology = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL;
info->rotation = get_dc_rotation(devmode);
info->scaling = DISPLAYCONFIG_SCALING_IDENTITY;
info->refreshRate.Numerator = devmode->dmDisplayFrequency;
info->refreshRate.Denominator = 1;
info->scanLineOrdering = get_dc_scanline_ordering(devmode);
info->targetAvailable = TRUE;
info->statusFlags = DISPLAYCONFIG_TARGET_IN_USE;
}
static void set_mode_source_info(DISPLAYCONFIG_MODE_INFO *info, const LUID *gpu_luid,
UINT32 source_id, const DEVMODEW *devmode)
{
DISPLAYCONFIG_SOURCE_MODE *mode = &(info->u.sourceMode);
info->infoType = DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE;
info->adapterId = *gpu_luid;
info->id = source_id;
mode->width = devmode->dmPelsWidth;
mode->height = devmode->dmPelsHeight;
mode->pixelFormat = get_dc_pixelformat(devmode->dmBitsPerPel);
if (devmode->dmFields & DM_POSITION)
{
mode->position = devmode->u1.s2.dmPosition;
}
else
{
mode->position.x = 0;
mode->position.y = 0;
}
}
static void set_path_source_info(DISPLAYCONFIG_PATH_SOURCE_INFO *info, const LUID *gpu_luid,
UINT32 source_id, UINT32 mode_index)
{
info->adapterId = *gpu_luid;
info->id = source_id;
info->u.modeInfoIdx = mode_index;
info->statusFlags = DISPLAYCONFIG_SOURCE_IN_USE;
}
static BOOL source_mode_exists(const DISPLAYCONFIG_MODE_INFO *modeinfo, UINT32 num_modes,
UINT32 source_id, UINT32 *found_mode_index)
{
UINT32 i;
for (i = 0; i < num_modes; i++)
{
if (modeinfo[i].infoType == DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE &&
modeinfo[i].id == source_id)
{
*found_mode_index = i;
return TRUE;
}
}
return FALSE;
}
/***********************************************************************
* QueryDisplayConfig (USER32.@)
*/
LONG WINAPI QueryDisplayConfig(UINT32 flags, UINT32 *numpathelements, DISPLAYCONFIG_PATH_INFO *pathinfo,
UINT32 *numinfoelements, DISPLAYCONFIG_MODE_INFO *modeinfo,
DISPLAYCONFIG_TOPOLOGY_ID *topologyid)
{
LONG adapter_index, ret;
HANDLE mutex;
HDEVINFO devinfo;
SP_DEVINFO_DATA device_data = {sizeof(device_data)};
DWORD monitor_index = 0, state_flags, type;
UINT32 output_id, source_mode_index, path_index = 0, mode_index = 0;
LUID gpu_luid;
WCHAR device_name[CCHDEVICENAME];
DEVMODEW devmode;
FIXME("(%08x %p %p %p %p %p): semi-stub\n", flags, numpathelements, pathinfo, numinfoelements, modeinfo, topologyid);
if (!numpathelements || !numinfoelements)
return ERROR_INVALID_PARAMETER;
if (!*numpathelements || !*numinfoelements)
return ERROR_INVALID_PARAMETER;
if (flags != QDC_ALL_PATHS &&
flags != QDC_ONLY_ACTIVE_PATHS &&
flags != QDC_DATABASE_CURRENT)
return ERROR_INVALID_PARAMETER;
if (((flags == QDC_DATABASE_CURRENT) && !topologyid) ||
((flags != QDC_DATABASE_CURRENT) && topologyid))
return ERROR_INVALID_PARAMETER;
if (flags != QDC_ONLY_ACTIVE_PATHS)
FIXME("only returning active paths\n");
if (topologyid)
{
FIXME("setting toplogyid to DISPLAYCONFIG_TOPOLOGY_INTERNAL\n");
*topologyid = DISPLAYCONFIG_TOPOLOGY_INTERNAL;
}
wait_graphics_driver_ready();
mutex = get_display_device_init_mutex();
/* Iterate through "targets"/monitors.
* Each target corresponds to a path, and each path corresponds to one or two unique modes.
*/
devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, L"DISPLAY", NULL, DIGCF_PRESENT);
if (devinfo == INVALID_HANDLE_VALUE)
{
ret = ERROR_GEN_FAILURE;
goto done;
}
ret = ERROR_GEN_FAILURE;
while (SetupDiEnumDeviceInfo(devinfo, monitor_index++, &device_data))
{
/* Only count active monitors */
if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS,
&type, (BYTE *)&state_flags, sizeof(state_flags), NULL, 0))
goto done;
if (!(state_flags & DISPLAY_DEVICE_ACTIVE))
continue;
if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPROPKEY_MONITOR_GPU_LUID,
&type, (BYTE *)&gpu_luid, sizeof(gpu_luid), NULL, 0))
goto done;
if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPROPKEY_MONITOR_OUTPUT_ID,
&type, (BYTE *)&output_id, sizeof(output_id), NULL, 0))
goto done;
if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_ADAPTERNAME,
&type, (BYTE *)device_name, sizeof(device_name), NULL, 0))
goto done;
memset(&devmode, 0, sizeof(devmode));
devmode.dmSize = sizeof(devmode);
if (!EnumDisplaySettingsW(device_name, ENUM_CURRENT_SETTINGS, &devmode))
goto done;
/* Extract the adapter index from device_name to use as the source ID */
adapter_index = wcstol(device_name + lstrlenW(L"\\\\.\\DISPLAY"), NULL, 10);
adapter_index--;
if (path_index == *numpathelements || mode_index == *numinfoelements)
{
ret = ERROR_INSUFFICIENT_BUFFER;
goto done;
}
pathinfo[path_index].flags = DISPLAYCONFIG_PATH_ACTIVE;
set_mode_target_info(&modeinfo[mode_index], &gpu_luid, output_id, flags, &devmode);
set_path_target_info(&(pathinfo[path_index].targetInfo), &gpu_luid, output_id, mode_index, &devmode);
mode_index++;
if (mode_index == *numinfoelements)
{
ret = ERROR_INSUFFICIENT_BUFFER;
goto done;
}
/* Multiple targets can be driven by the same source, ensure a mode
* hasn't already been added for this source.
*/
if (!source_mode_exists(modeinfo, mode_index, adapter_index, &source_mode_index))
{
set_mode_source_info(&modeinfo[mode_index], &gpu_luid, adapter_index, &devmode);
source_mode_index = mode_index;
mode_index++;
}
set_path_source_info(&(pathinfo[path_index].sourceInfo), &gpu_luid, adapter_index, source_mode_index);
path_index++;
}
*numpathelements = path_index;
*numinfoelements = mode_index;
ret = ERROR_SUCCESS;
done:
SetupDiDestroyDeviceInfoList(devinfo);
release_display_device_init_mutex(mutex);
return ret;
}
/***********************************************************************
* DisplayConfigGetDeviceInfo (USER32.@)
*/
LONG WINAPI DisplayConfigGetDeviceInfo(DISPLAYCONFIG_DEVICE_INFO_HEADER *packet)
{
LONG ret = ERROR_GEN_FAILURE;
HANDLE mutex;
HDEVINFO devinfo;
SP_DEVINFO_DATA device_data = {sizeof(device_data)};
DWORD index = 0, type;
LUID gpu_luid;
TRACE("(%p)\n", packet);
if (!packet || packet->size < sizeof(*packet))
return ERROR_GEN_FAILURE;
wait_graphics_driver_ready();
switch (packet->type)
{
case DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME:
{
DISPLAYCONFIG_SOURCE_DEVICE_NAME *source_name = (DISPLAYCONFIG_SOURCE_DEVICE_NAME *)packet;
WCHAR device_name[CCHDEVICENAME];
LONG source_id;
TRACE("DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME\n");
if (packet->size < sizeof(*source_name))
return ERROR_INVALID_PARAMETER;
mutex = get_display_device_init_mutex();
devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, L"DISPLAY", NULL, DIGCF_PRESENT);
if (devinfo == INVALID_HANDLE_VALUE)
{
release_display_device_init_mutex(mutex);
return ret;
}
while (SetupDiEnumDeviceInfo(devinfo, index++, &device_data))
{
if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPROPKEY_MONITOR_GPU_LUID,
&type, (BYTE *)&gpu_luid, sizeof(gpu_luid), NULL, 0))
continue;
if ((source_name->header.adapterId.LowPart != gpu_luid.LowPart) ||
(source_name->header.adapterId.HighPart != gpu_luid.HighPart))
continue;
/* QueryDisplayConfig() derives the source ID from the adapter name. */
if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_ADAPTERNAME,
&type, (BYTE *)device_name, sizeof(device_name), NULL, 0))
continue;
source_id = wcstol(device_name + lstrlenW(L"\\\\.\\DISPLAY"), NULL, 10);
source_id--;
if (source_name->header.id != source_id)
continue;
lstrcpyW(source_name->viewGdiDeviceName, device_name);
ret = ERROR_SUCCESS;
break;
}
SetupDiDestroyDeviceInfoList(devinfo);
release_display_device_init_mutex(mutex);
return ret;
}
case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME:
{
DISPLAYCONFIG_TARGET_DEVICE_NAME *target_name = (DISPLAYCONFIG_TARGET_DEVICE_NAME *)packet;
FIXME("DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME: stub\n");
if (packet->size < sizeof(*target_name))
return ERROR_INVALID_PARAMETER;
return ERROR_NOT_SUPPORTED;
}
case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE:
{
DISPLAYCONFIG_TARGET_PREFERRED_MODE *preferred_mode = (DISPLAYCONFIG_TARGET_PREFERRED_MODE *)packet;
FIXME("DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE: stub\n");
if (packet->size < sizeof(*preferred_mode))
return ERROR_INVALID_PARAMETER;
return ERROR_NOT_SUPPORTED;
}
case DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME:
{
DISPLAYCONFIG_ADAPTER_NAME *adapter_name = (DISPLAYCONFIG_ADAPTER_NAME *)packet;
FIXME("DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME: stub\n");
if (packet->size < sizeof(*adapter_name))
return ERROR_INVALID_PARAMETER;
return ERROR_NOT_SUPPORTED;
}
case DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE:
case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE:
case DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION:
case DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION:
case DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO:
case DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE:
case DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL:
default:
FIXME("Unimplemented packet type: %u\n", packet->type);
return ERROR_INVALID_PARAMETER;
}
}
/***********************************************************************
* SetDisplayConfig (USER32.@)
*/
LONG WINAPI SetDisplayConfig(UINT32 path_info_count, DISPLAYCONFIG_PATH_INFO *path_info, UINT32 mode_info_count,
DISPLAYCONFIG_MODE_INFO *mode_info, UINT32 flags)
{
FIXME("path_info_count %u, path_info %p, mode_info_count %u, mode_info %p, flags %#x stub.\n",
path_info_count, path_info, mode_info_count, mode_info, flags);
return ERROR_SUCCESS;
}