kernel32: Update version to Win 10.
[wine.git] / dlls / user32 / sysparams.c
blob55d6d7e53a7f8948562532046676b5613e8a6285
1 /*
2 * System parameters functions
4 * Copyright 1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <assert.h>
22 #include <limits.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <wchar.h>
29 #define NONAMELESSUNION
30 #define NONAMELESSSTRUCT
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winnls.h"
35 #include "wingdi.h"
36 #include "winuser.h"
37 #include "winreg.h"
38 #include "wine/wingdi16.h"
39 #include "winerror.h"
41 #include "initguid.h"
42 #include "d3dkmdt.h"
43 #include "devguid.h"
44 #include "setupapi.h"
45 #include "controls.h"
46 #include "win.h"
47 #include "user_private.h"
48 #include "wine/gdi_driver.h"
49 #include "wine/asm.h"
50 #include "wine/debug.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(system);
54 /* System parameter indexes */
55 enum spi_index
57 SPI_SETWORKAREA_IDX,
58 SPI_INDEX_COUNT
61 /**
62 * Names of the registry subkeys of HKEY_CURRENT_USER key and value names
63 * for the system parameters.
66 /* the various registry keys that are used to store parameters */
67 enum parameter_key
69 COLORS_KEY,
70 DESKTOP_KEY,
71 KEYBOARD_KEY,
72 MOUSE_KEY,
73 METRICS_KEY,
74 SOUND_KEY,
75 VERSION_KEY,
76 SHOWSOUNDS_KEY,
77 KEYBOARDPREF_KEY,
78 SCREENREADER_KEY,
79 AUDIODESC_KEY,
80 NB_PARAM_KEYS
83 static const WCHAR *parameter_key_names[NB_PARAM_KEYS] =
85 L"Control Panel\\Colors",
86 L"Control Panel\\Desktop",
87 L"Control Panel\\Keyboard",
88 L"Control Panel\\Mouse",
89 L"Control Panel\\Desktop\\WindowMetrics",
90 L"Control Panel\\Sound",
91 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows",
92 L"Control Panel\\Accessibility\\ShowSounds",
93 L"Control Panel\\Accessibility\\Keyboard Preference",
94 L"Control Panel\\Accessibility\\Blind Access",
95 L"Control Panel\\Accessibility\\AudioDescription",
98 DEFINE_DEVPROPKEY(DEVPROPKEY_GPU_LUID, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6, 2);
99 DEFINE_DEVPROPKEY(DEVPROPKEY_MONITOR_GPU_LUID, 0xca085853, 0x16ce, 0x48aa, 0xb1, 0x14, 0xde, 0x9c, 0x72, 0x33, 0x42, 0x23, 1);
100 DEFINE_DEVPROPKEY(DEVPROPKEY_MONITOR_OUTPUT_ID, 0xca085853, 0x16ce, 0x48aa, 0xb1, 0x14, 0xde, 0x9c, 0x72, 0x33, 0x42, 0x23, 2);
102 /* Wine specific monitor properties */
103 DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_STATEFLAGS, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 2);
104 DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_RCMONITOR, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 3);
105 DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_RCWORK, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 4);
106 DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_ADAPTERNAME, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 5);
108 #define NULLDRV_DEFAULT_HMONITOR ((HMONITOR)(UINT_PTR)(0x10000 + 1))
110 /* Cached monitor information */
111 static MONITORINFOEXW *monitors;
112 static UINT monitor_count;
113 static FILETIME last_query_monitors_time;
114 static CRITICAL_SECTION monitors_section;
115 static CRITICAL_SECTION_DEBUG monitors_critsect_debug =
117 0, 0, &monitors_section,
118 { &monitors_critsect_debug.ProcessLocksList, &monitors_critsect_debug.ProcessLocksList },
119 0, 0, { (DWORD_PTR)(__FILE__ ": monitors_section") }
121 static CRITICAL_SECTION monitors_section = { &monitors_critsect_debug, -1 , 0, 0, 0, 0 };
123 static HDC display_dc;
124 static CRITICAL_SECTION display_dc_section;
125 static CRITICAL_SECTION_DEBUG critsect_debug =
127 0, 0, &display_dc_section,
128 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
129 0, 0, { (DWORD_PTR)(__FILE__ ": display_dc_section") }
131 static CRITICAL_SECTION display_dc_section = { &critsect_debug, -1 ,0, 0, 0, 0 };
134 /* Indicators whether system parameter value is loaded */
135 static char spi_loaded[SPI_INDEX_COUNT];
137 static BOOL notify_change = TRUE;
139 /* System parameters storage */
140 static RECT work_area;
141 static UINT system_dpi;
142 static DPI_AWARENESS dpi_awareness;
143 static DPI_AWARENESS default_awareness = DPI_AWARENESS_UNAWARE;
145 static HKEY volatile_base_key;
146 static HKEY video_key;
148 union sysparam_all_entry;
150 struct sysparam_entry
152 BOOL (*get)( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi );
153 BOOL (*set)( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags );
154 BOOL (*init)( union sysparam_all_entry *entry );
155 enum parameter_key base_key;
156 const WCHAR *regval;
157 enum parameter_key mirror_key;
158 const WCHAR *mirror;
159 BOOL loaded;
162 struct sysparam_uint_entry
164 struct sysparam_entry hdr;
165 UINT val;
168 struct sysparam_bool_entry
170 struct sysparam_entry hdr;
171 BOOL val;
174 struct sysparam_dword_entry
176 struct sysparam_entry hdr;
177 DWORD val;
180 struct sysparam_rgb_entry
182 struct sysparam_entry hdr;
183 COLORREF val;
184 HBRUSH brush;
185 HPEN pen;
188 struct sysparam_binary_entry
190 struct sysparam_entry hdr;
191 void *ptr;
192 size_t size;
195 struct sysparam_path_entry
197 struct sysparam_entry hdr;
198 WCHAR path[MAX_PATH];
201 struct sysparam_font_entry
203 struct sysparam_entry hdr;
204 UINT weight;
205 LOGFONTW val;
206 WCHAR fullname[LF_FACESIZE];
209 struct sysparam_pref_entry
211 struct sysparam_entry hdr;
212 struct sysparam_binary_entry *parent;
213 UINT offset;
214 UINT mask;
217 union sysparam_all_entry
219 struct sysparam_entry hdr;
220 struct sysparam_uint_entry uint;
221 struct sysparam_bool_entry bool;
222 struct sysparam_dword_entry dword;
223 struct sysparam_rgb_entry rgb;
224 struct sysparam_binary_entry bin;
225 struct sysparam_path_entry path;
226 struct sysparam_font_entry font;
227 struct sysparam_pref_entry pref;
230 static void SYSPARAMS_LogFont16To32W( const LOGFONT16 *font16, LPLOGFONTW font32 )
232 font32->lfHeight = font16->lfHeight;
233 font32->lfWidth = font16->lfWidth;
234 font32->lfEscapement = font16->lfEscapement;
235 font32->lfOrientation = font16->lfOrientation;
236 font32->lfWeight = font16->lfWeight;
237 font32->lfItalic = font16->lfItalic;
238 font32->lfUnderline = font16->lfUnderline;
239 font32->lfStrikeOut = font16->lfStrikeOut;
240 font32->lfCharSet = font16->lfCharSet;
241 font32->lfOutPrecision = font16->lfOutPrecision;
242 font32->lfClipPrecision = font16->lfClipPrecision;
243 font32->lfQuality = font16->lfQuality;
244 font32->lfPitchAndFamily = font16->lfPitchAndFamily;
245 MultiByteToWideChar( CP_ACP, 0, font16->lfFaceName, -1, font32->lfFaceName, LF_FACESIZE );
246 font32->lfFaceName[LF_FACESIZE-1] = 0;
249 static void SYSPARAMS_LogFont32WTo32A( const LOGFONTW* font32W, LPLOGFONTA font32A )
251 font32A->lfHeight = font32W->lfHeight;
252 font32A->lfWidth = font32W->lfWidth;
253 font32A->lfEscapement = font32W->lfEscapement;
254 font32A->lfOrientation = font32W->lfOrientation;
255 font32A->lfWeight = font32W->lfWeight;
256 font32A->lfItalic = font32W->lfItalic;
257 font32A->lfUnderline = font32W->lfUnderline;
258 font32A->lfStrikeOut = font32W->lfStrikeOut;
259 font32A->lfCharSet = font32W->lfCharSet;
260 font32A->lfOutPrecision = font32W->lfOutPrecision;
261 font32A->lfClipPrecision = font32W->lfClipPrecision;
262 font32A->lfQuality = font32W->lfQuality;
263 font32A->lfPitchAndFamily = font32W->lfPitchAndFamily;
264 WideCharToMultiByte( CP_ACP, 0, font32W->lfFaceName, -1, font32A->lfFaceName, LF_FACESIZE, NULL, NULL );
265 font32A->lfFaceName[LF_FACESIZE-1] = 0;
268 static void SYSPARAMS_LogFont32ATo32W( const LOGFONTA* font32A, LPLOGFONTW font32W )
270 font32W->lfHeight = font32A->lfHeight;
271 font32W->lfWidth = font32A->lfWidth;
272 font32W->lfEscapement = font32A->lfEscapement;
273 font32W->lfOrientation = font32A->lfOrientation;
274 font32W->lfWeight = font32A->lfWeight;
275 font32W->lfItalic = font32A->lfItalic;
276 font32W->lfUnderline = font32A->lfUnderline;
277 font32W->lfStrikeOut = font32A->lfStrikeOut;
278 font32W->lfCharSet = font32A->lfCharSet;
279 font32W->lfOutPrecision = font32A->lfOutPrecision;
280 font32W->lfClipPrecision = font32A->lfClipPrecision;
281 font32W->lfQuality = font32A->lfQuality;
282 font32W->lfPitchAndFamily = font32A->lfPitchAndFamily;
283 MultiByteToWideChar( CP_ACP, 0, font32A->lfFaceName, -1, font32W->lfFaceName, LF_FACESIZE );
284 font32W->lfFaceName[LF_FACESIZE-1] = 0;
287 static void SYSPARAMS_NonClientMetrics32WTo32A( const NONCLIENTMETRICSW* lpnm32W, LPNONCLIENTMETRICSA lpnm32A )
289 lpnm32A->iBorderWidth = lpnm32W->iBorderWidth;
290 lpnm32A->iScrollWidth = lpnm32W->iScrollWidth;
291 lpnm32A->iScrollHeight = lpnm32W->iScrollHeight;
292 lpnm32A->iCaptionWidth = lpnm32W->iCaptionWidth;
293 lpnm32A->iCaptionHeight = lpnm32W->iCaptionHeight;
294 SYSPARAMS_LogFont32WTo32A( &lpnm32W->lfCaptionFont, &lpnm32A->lfCaptionFont );
295 lpnm32A->iSmCaptionWidth = lpnm32W->iSmCaptionWidth;
296 lpnm32A->iSmCaptionHeight = lpnm32W->iSmCaptionHeight;
297 SYSPARAMS_LogFont32WTo32A( &lpnm32W->lfSmCaptionFont, &lpnm32A->lfSmCaptionFont );
298 lpnm32A->iMenuWidth = lpnm32W->iMenuWidth;
299 lpnm32A->iMenuHeight = lpnm32W->iMenuHeight;
300 SYSPARAMS_LogFont32WTo32A( &lpnm32W->lfMenuFont, &lpnm32A->lfMenuFont );
301 SYSPARAMS_LogFont32WTo32A( &lpnm32W->lfStatusFont, &lpnm32A->lfStatusFont );
302 SYSPARAMS_LogFont32WTo32A( &lpnm32W->lfMessageFont, &lpnm32A->lfMessageFont );
303 if (lpnm32A->cbSize > FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth))
305 if (lpnm32W->cbSize > FIELD_OFFSET(NONCLIENTMETRICSW, iPaddedBorderWidth))
306 lpnm32A->iPaddedBorderWidth = lpnm32W->iPaddedBorderWidth;
307 else
308 lpnm32A->iPaddedBorderWidth = 0;
312 static void SYSPARAMS_NonClientMetrics32ATo32W( const NONCLIENTMETRICSA* lpnm32A, LPNONCLIENTMETRICSW lpnm32W )
314 lpnm32W->iBorderWidth = lpnm32A->iBorderWidth;
315 lpnm32W->iScrollWidth = lpnm32A->iScrollWidth;
316 lpnm32W->iScrollHeight = lpnm32A->iScrollHeight;
317 lpnm32W->iCaptionWidth = lpnm32A->iCaptionWidth;
318 lpnm32W->iCaptionHeight = lpnm32A->iCaptionHeight;
319 SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfCaptionFont, &lpnm32W->lfCaptionFont );
320 lpnm32W->iSmCaptionWidth = lpnm32A->iSmCaptionWidth;
321 lpnm32W->iSmCaptionHeight = lpnm32A->iSmCaptionHeight;
322 SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfSmCaptionFont, &lpnm32W->lfSmCaptionFont );
323 lpnm32W->iMenuWidth = lpnm32A->iMenuWidth;
324 lpnm32W->iMenuHeight = lpnm32A->iMenuHeight;
325 SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfMenuFont, &lpnm32W->lfMenuFont );
326 SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfStatusFont, &lpnm32W->lfStatusFont );
327 SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfMessageFont, &lpnm32W->lfMessageFont );
328 if (lpnm32W->cbSize > FIELD_OFFSET(NONCLIENTMETRICSW, iPaddedBorderWidth))
330 if (lpnm32A->cbSize > FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth))
331 lpnm32W->iPaddedBorderWidth = lpnm32A->iPaddedBorderWidth;
332 else
333 lpnm32W->iPaddedBorderWidth = 0;
338 /* Helper functions to retrieve monitors info */
340 struct monitor_info
342 int count;
343 RECT primary_rect;
344 RECT virtual_rect;
347 static BOOL CALLBACK monitor_info_proc( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
349 MONITORINFO mi;
350 struct monitor_info *info = (struct monitor_info *)lp;
351 info->count++;
352 UnionRect( &info->virtual_rect, &info->virtual_rect, rect );
353 mi.cbSize = sizeof(mi);
354 if (GetMonitorInfoW( monitor, &mi ) && (mi.dwFlags & MONITORINFOF_PRIMARY))
355 info->primary_rect = mi.rcMonitor;
356 return TRUE;
359 static void get_monitors_info( struct monitor_info *info )
361 info->count = 0;
362 SetRectEmpty( &info->primary_rect );
363 SetRectEmpty( &info->virtual_rect );
364 EnumDisplayMonitors( 0, NULL, monitor_info_proc, (LPARAM)info );
367 RECT get_virtual_screen_rect(void)
369 struct monitor_info info;
370 get_monitors_info( &info );
371 return info.virtual_rect;
374 static BOOL get_primary_adapter(WCHAR *name)
376 DISPLAY_DEVICEW dd;
377 DWORD i;
379 dd.cb = sizeof(dd);
380 for (i = 0; EnumDisplayDevicesW(NULL, i, &dd, 0); ++i)
382 if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
384 lstrcpyW(name, dd.DeviceName);
385 return TRUE;
389 return FALSE;
392 static BOOL is_valid_adapter_name(const WCHAR *name)
394 long int adapter_idx;
395 WCHAR *end;
397 if (wcsnicmp(name, L"\\\\.\\DISPLAY", lstrlenW(L"\\\\.\\DISPLAY")))
398 return FALSE;
400 adapter_idx = wcstol(name + lstrlenW(L"\\\\.\\DISPLAY"), &end, 10);
401 if (*end || adapter_idx < 1)
402 return FALSE;
404 return TRUE;
407 /* get text metrics and/or "average" char width of the specified logfont
408 * for the specified dc */
409 static void get_text_metr_size( HDC hdc, LOGFONTW *plf, TEXTMETRICW * ptm, UINT *psz)
411 HFONT hfont, hfontsav;
412 TEXTMETRICW tm;
413 if( !ptm) ptm = &tm;
414 hfont = CreateFontIndirectW( plf);
415 if( !hfont || ( hfontsav = SelectObject( hdc, hfont)) == NULL ) {
416 ptm->tmHeight = -1;
417 if( psz) *psz = 10;
418 if( hfont) DeleteObject( hfont);
419 return;
421 GetTextMetricsW( hdc, ptm);
422 if( psz)
423 if( !(*psz = GdiGetCharDimensions( hdc, ptm, NULL)))
424 *psz = 10;
425 SelectObject( hdc, hfontsav);
426 DeleteObject( hfont);
429 /***********************************************************************
430 * SYSPARAMS_NotifyChange
432 * Sends notification about system parameter update.
434 static void SYSPARAMS_NotifyChange( UINT uiAction, UINT fWinIni )
436 static const WCHAR emptyW[1];
438 if (notify_change)
440 if (fWinIni & SPIF_UPDATEINIFILE)
442 if (fWinIni & (SPIF_SENDWININICHANGE | SPIF_SENDCHANGE))
443 SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE,
444 uiAction, (LPARAM) emptyW,
445 SMTO_ABORTIFHUNG, 2000, NULL );
447 else
449 /* FIXME notify other wine processes with internal message */
454 /* retrieve the cached base keys for a given entry */
455 static BOOL get_base_keys( enum parameter_key index, HKEY *base_key, HKEY *volatile_key )
457 static HKEY base_keys[NB_PARAM_KEYS];
458 static HKEY volatile_keys[NB_PARAM_KEYS];
459 HKEY key;
461 if (!base_keys[index] && base_key)
463 if (RegCreateKeyW( HKEY_CURRENT_USER, parameter_key_names[index], &key )) return FALSE;
464 if (InterlockedCompareExchangePointer( (void **)&base_keys[index], key, 0 ))
465 RegCloseKey( key );
467 if (!volatile_keys[index] && volatile_key)
469 if (RegCreateKeyExW( volatile_base_key, parameter_key_names[index],
470 0, 0, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &key, 0 )) return FALSE;
471 if (InterlockedCompareExchangePointer( (void **)&volatile_keys[index], key, 0 ))
472 RegCloseKey( key );
474 if (base_key) *base_key = base_keys[index];
475 if (volatile_key) *volatile_key = volatile_keys[index];
476 return TRUE;
479 /* load a value to a registry entry */
480 static DWORD load_entry( struct sysparam_entry *entry, void *data, DWORD size )
482 DWORD type, count;
483 HKEY base_key, volatile_key;
485 if (!get_base_keys( entry->base_key, &base_key, &volatile_key )) return FALSE;
487 count = size;
488 if (RegQueryValueExW( volatile_key, entry->regval, NULL, &type, data, &count ))
490 count = size;
491 if (RegQueryValueExW( base_key, entry->regval, NULL, &type, data, &count )) count = 0;
493 /* make sure strings are null-terminated */
494 if (size && count == size && type == REG_SZ) ((WCHAR *)data)[count / sizeof(WCHAR) - 1] = 0;
495 entry->loaded = TRUE;
496 return count;
499 /* save a value to a registry entry */
500 static BOOL save_entry( const struct sysparam_entry *entry, const void *data, DWORD size,
501 DWORD type, UINT flags )
503 HKEY base_key, volatile_key;
505 if (flags & SPIF_UPDATEINIFILE)
507 if (!get_base_keys( entry->base_key, &base_key, &volatile_key )) return FALSE;
508 if (RegSetValueExW( base_key, entry->regval, 0, type, data, size )) return FALSE;
509 RegDeleteValueW( volatile_key, entry->regval );
511 if (entry->mirror && get_base_keys( entry->mirror_key, &base_key, NULL ))
512 RegSetValueExW( base_key, entry->mirror, 0, type, data, size );
514 else
516 if (!get_base_keys( entry->base_key, NULL, &volatile_key )) return FALSE;
517 if (RegSetValueExW( volatile_key, entry->regval, 0, type, data, size )) return FALSE;
519 return TRUE;
522 /* save a string value to a registry entry */
523 static BOOL save_entry_string( const struct sysparam_entry *entry, const WCHAR *str, UINT flags )
525 return save_entry( entry, str, (lstrlenW(str) + 1) * sizeof(WCHAR), REG_SZ, flags );
528 /* initialize an entry in the registry if missing */
529 static BOOL init_entry( struct sysparam_entry *entry, const void *data, DWORD size, DWORD type )
531 HKEY base_key;
533 if (!get_base_keys( entry->base_key, &base_key, NULL )) return FALSE;
534 if (!RegQueryValueExW( base_key, entry->regval, NULL, NULL, NULL, NULL )) return TRUE;
535 if (RegSetValueExW( base_key, entry->regval, 0, type, data, size )) return FALSE;
536 if (entry->mirror && get_base_keys( entry->mirror_key, &base_key, NULL ))
537 RegSetValueExW( base_key, entry->mirror, 0, type, data, size );
538 entry->loaded = TRUE;
539 return TRUE;
542 /* initialize a string value in the registry if missing */
543 static BOOL init_entry_string( struct sysparam_entry *entry, const WCHAR *str )
545 return init_entry( entry, str, (lstrlenW(str) + 1) * sizeof(WCHAR), REG_SZ );
548 HDC get_display_dc(void)
550 EnterCriticalSection( &display_dc_section );
551 if (!display_dc)
553 HDC dc;
555 LeaveCriticalSection( &display_dc_section );
556 dc = CreateDCW( L"DISPLAY", NULL, NULL, NULL );
557 EnterCriticalSection( &display_dc_section );
558 if (display_dc)
559 DeleteDC(dc);
560 else
561 display_dc = dc;
563 return display_dc;
566 void release_display_dc( HDC hdc )
568 LeaveCriticalSection( &display_dc_section );
571 static HANDLE get_display_device_init_mutex( void )
573 HANDLE mutex = CreateMutexW( NULL, FALSE, L"display_device_init" );
575 WaitForSingleObject( mutex, INFINITE );
576 return mutex;
579 static void release_display_device_init_mutex( HANDLE mutex )
581 ReleaseMutex( mutex );
582 CloseHandle( mutex );
585 /* Wait until graphics driver is loaded by explorer */
586 static void wait_graphics_driver_ready(void)
588 static BOOL ready = FALSE;
590 if (!ready)
592 SendMessageW( GetDesktopWindow(), WM_NULL, 0, 0 );
593 ready = TRUE;
597 /* map value from system dpi to standard 96 dpi for storing in the registry */
598 static int map_from_system_dpi( int val )
600 return MulDiv( val, USER_DEFAULT_SCREEN_DPI, GetDpiForSystem() );
603 /* map value from 96 dpi to system or custom dpi */
604 static int map_to_dpi( int val, UINT dpi )
606 if (!dpi) dpi = GetDpiForSystem();
607 return MulDiv( val, dpi, USER_DEFAULT_SCREEN_DPI );
610 static INT CALLBACK real_fontname_proc(const LOGFONTW *lf, const TEXTMETRICW *ntm, DWORD type, LPARAM lparam)
612 const ENUMLOGFONTW *elf = (const ENUMLOGFONTW *)lf;
613 WCHAR *fullname = (WCHAR *)lparam;
615 lstrcpynW( fullname, elf->elfFullName, LF_FACESIZE );
616 return 0;
619 static void get_real_fontname( LOGFONTW *lf, WCHAR fullname[LF_FACESIZE] )
621 HDC hdc = get_display_dc();
622 lstrcpyW( fullname, lf->lfFaceName );
623 EnumFontFamiliesExW( hdc, lf, real_fontname_proc, (LPARAM)fullname, 0 );
624 release_display_dc( hdc );
627 /* adjust some of the raw values found in the registry */
628 static void normalize_nonclientmetrics( NONCLIENTMETRICSW *pncm)
630 TEXTMETRICW tm;
631 HDC hdc = get_display_dc();
633 if( pncm->iBorderWidth < 1) pncm->iBorderWidth = 1;
634 if( pncm->iCaptionWidth < 8) pncm->iCaptionWidth = 8;
635 if( pncm->iScrollWidth < 8) pncm->iScrollWidth = 8;
636 if( pncm->iScrollHeight < 8) pncm->iScrollHeight = 8;
638 /* adjust some heights to the corresponding font */
639 get_text_metr_size( hdc, &pncm->lfMenuFont, &tm, NULL);
640 pncm->iMenuHeight = max( pncm->iMenuHeight, 2 + tm.tmHeight + tm.tmExternalLeading );
641 get_text_metr_size( hdc, &pncm->lfCaptionFont, &tm, NULL);
642 pncm->iCaptionHeight = max( pncm->iCaptionHeight, 2 + tm.tmHeight);
643 get_text_metr_size( hdc, &pncm->lfSmCaptionFont, &tm, NULL);
644 pncm->iSmCaptionHeight = max( pncm->iSmCaptionHeight, 2 + tm.tmHeight);
645 release_display_dc( hdc );
648 static BOOL CALLBACK enum_monitors( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
650 MONITORINFO mi;
652 mi.cbSize = sizeof(mi);
653 if (GetMonitorInfoW( monitor, &mi ) && (mi.dwFlags & MONITORINFOF_PRIMARY))
655 LPRECT work = (LPRECT)lp;
656 *work = mi.rcWork;
657 return FALSE;
659 return TRUE;
662 /* load a uint parameter from the registry */
663 static BOOL get_uint_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
665 if (!ptr_param) return FALSE;
667 if (!entry->hdr.loaded)
669 WCHAR buf[32];
671 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->uint.val = wcstol( buf, NULL, 10 );
673 *(UINT *)ptr_param = entry->uint.val;
674 return TRUE;
677 /* set a uint parameter in the registry */
678 static BOOL set_uint_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
680 WCHAR buf[32];
682 wsprintfW( buf, L"%u", int_param );
683 if (!save_entry_string( &entry->hdr, buf, flags )) return FALSE;
684 entry->uint.val = int_param;
685 entry->hdr.loaded = TRUE;
686 return TRUE;
689 /* initialize a uint parameter */
690 static BOOL init_uint_entry( union sysparam_all_entry *entry )
692 WCHAR buf[32];
694 wsprintfW( buf, L"%u", entry->uint.val );
695 return init_entry_string( &entry->hdr, buf );
698 /* set an int parameter in the registry */
699 static BOOL set_int_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
701 WCHAR buf[32];
703 wsprintfW( buf, L"%d", int_param );
704 if (!save_entry_string( &entry->hdr, buf, flags )) return FALSE;
705 entry->uint.val = int_param;
706 entry->hdr.loaded = TRUE;
707 return TRUE;
710 /* initialize an int parameter */
711 static BOOL init_int_entry( union sysparam_all_entry *entry )
713 WCHAR buf[32];
715 wsprintfW( buf, L"%d", entry->uint.val );
716 return init_entry_string( &entry->hdr, buf );
719 /* load a twips parameter from the registry */
720 static BOOL get_twips_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
722 int val;
724 if (!ptr_param) return FALSE;
726 if (!entry->hdr.loaded)
728 WCHAR buf[32];
730 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->uint.val = wcstol( buf, NULL, 10 );
733 /* Dimensions are quoted as being "twips" values if negative and pixels if positive.
734 * One inch is 1440 twips.
735 * See for example
736 * Technical Reference to the Windows 2000 Registry ->
737 * HKEY_CURRENT_USER -> Control Panel -> Desktop -> WindowMetrics
739 val = entry->uint.val;
740 if (val < 0)
741 val = MulDiv( -val, dpi, 1440 );
742 else
743 val = map_to_dpi( val, dpi );
745 *(int *)ptr_param = val;
746 return TRUE;
749 /* set a twips parameter in the registry */
750 static BOOL set_twips_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
752 int val = int_param;
753 if (val > 0) val = map_from_system_dpi( val );
754 return set_int_entry( entry, val, ptr_param, flags );
757 /* load a bool parameter from the registry */
758 static BOOL get_bool_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
760 if (!ptr_param) return FALSE;
762 if (!entry->hdr.loaded)
764 WCHAR buf[32];
766 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->bool.val = wcstol( buf, NULL, 10 ) != 0;
768 *(UINT *)ptr_param = entry->bool.val;
769 return TRUE;
772 /* set a bool parameter in the registry */
773 static BOOL set_bool_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
775 WCHAR buf[32];
777 wsprintfW( buf, L"%u", int_param != 0 );
778 if (!save_entry_string( &entry->hdr, buf, flags )) return FALSE;
779 entry->bool.val = int_param != 0;
780 entry->hdr.loaded = TRUE;
781 return TRUE;
784 /* initialize a bool parameter */
785 static BOOL init_bool_entry( union sysparam_all_entry *entry )
787 WCHAR buf[32];
789 wsprintfW( buf, L"%u", entry->bool.val != 0 );
790 return init_entry_string( &entry->hdr, buf );
793 /* load a bool parameter using Yes/No strings from the registry */
794 static BOOL get_yesno_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
796 if (!ptr_param) return FALSE;
798 if (!entry->hdr.loaded)
800 WCHAR buf[32];
802 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->bool.val = !lstrcmpiW( L"Yes", buf );
804 *(UINT *)ptr_param = entry->bool.val;
805 return TRUE;
808 /* set a bool parameter using Yes/No strings from the registry */
809 static BOOL set_yesno_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
811 const WCHAR *str = int_param ? L"Yes" : L"No";
813 if (!save_entry_string( &entry->hdr, str, flags )) return FALSE;
814 entry->bool.val = int_param != 0;
815 entry->hdr.loaded = TRUE;
816 return TRUE;
819 /* initialize a bool parameter using Yes/No strings */
820 static BOOL init_yesno_entry( union sysparam_all_entry *entry )
822 return init_entry_string( &entry->hdr, entry->bool.val ? L"Yes" : L"No" );
825 /* load a dword (binary) parameter from the registry */
826 static BOOL get_dword_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
828 if (!ptr_param) return FALSE;
830 if (!entry->hdr.loaded)
832 DWORD val;
833 if (load_entry( &entry->hdr, &val, sizeof(val) ) == sizeof(DWORD)) entry->dword.val = val;
835 *(DWORD *)ptr_param = entry->dword.val;
836 return TRUE;
839 /* set a dword (binary) parameter in the registry */
840 static BOOL set_dword_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
842 DWORD val = PtrToUlong( ptr_param );
844 if (!save_entry( &entry->hdr, &val, sizeof(val), REG_DWORD, flags )) return FALSE;
845 entry->dword.val = val;
846 entry->hdr.loaded = TRUE;
847 return TRUE;
850 /* initialize a dword parameter */
851 static BOOL init_dword_entry( union sysparam_all_entry *entry )
853 return init_entry( &entry->hdr, &entry->dword.val, sizeof(entry->dword.val), REG_DWORD );
856 /* load an RGB parameter from the registry */
857 static BOOL get_rgb_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
859 if (!ptr_param) return FALSE;
861 if (!entry->hdr.loaded)
863 WCHAR buf[32];
865 if (load_entry( &entry->hdr, buf, sizeof(buf) ))
867 DWORD r, g, b;
868 WCHAR *end, *str = buf;
870 r = wcstoul( str, &end, 10 );
871 if (end == str || !*end) goto done;
872 str = end + 1;
873 g = wcstoul( str, &end, 10 );
874 if (end == str || !*end) goto done;
875 str = end + 1;
876 b = wcstoul( str, &end, 10 );
877 if (end == str) goto done;
878 if (r > 255 || g > 255 || b > 255) goto done;
879 entry->rgb.val = RGB( r, g, b );
882 done:
883 *(COLORREF *)ptr_param = entry->rgb.val;
884 return TRUE;
887 /* set an RGB parameter in the registry */
888 static BOOL set_rgb_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
890 WCHAR buf[32];
891 HBRUSH brush;
892 HPEN pen;
894 wsprintfW( buf, L"%u %u %u", GetRValue(int_param), GetGValue(int_param), GetBValue(int_param) );
895 if (!save_entry_string( &entry->hdr, buf, flags )) return FALSE;
896 entry->rgb.val = int_param;
897 entry->hdr.loaded = TRUE;
898 if ((brush = InterlockedExchangePointer( (void **)&entry->rgb.brush, 0 )))
900 __wine_make_gdi_object_system( brush, FALSE );
901 DeleteObject( brush );
903 if ((pen = InterlockedExchangePointer( (void **)&entry->rgb.pen, 0 )))
905 __wine_make_gdi_object_system( pen, FALSE );
906 DeleteObject( pen );
908 return TRUE;
911 /* initialize an RGB parameter */
912 static BOOL init_rgb_entry( union sysparam_all_entry *entry )
914 WCHAR buf[32];
916 wsprintfW( buf, L"%u %u %u", GetRValue(entry->rgb.val), GetGValue(entry->rgb.val), GetBValue(entry->rgb.val) );
917 return init_entry_string( &entry->hdr, buf );
920 /* load a font (binary) parameter from the registry */
921 static BOOL get_font_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
923 LOGFONTW font;
925 if (!ptr_param) return FALSE;
927 if (!entry->hdr.loaded)
929 switch (load_entry( &entry->hdr, &font, sizeof(font) ))
931 case sizeof(font):
932 if (font.lfHeight > 0) /* positive height value means points ( inch/72 ) */
933 font.lfHeight = -MulDiv( font.lfHeight, USER_DEFAULT_SCREEN_DPI, 72 );
934 entry->font.val = font;
935 break;
936 case sizeof(LOGFONT16): /* win9x-winME format */
937 SYSPARAMS_LogFont16To32W( (LOGFONT16 *)&font, &entry->font.val );
938 if (entry->font.val.lfHeight > 0)
939 entry->font.val.lfHeight = -MulDiv( entry->font.val.lfHeight, USER_DEFAULT_SCREEN_DPI, 72 );
940 break;
941 default:
942 WARN( "Unknown format in key %s value %s\n",
943 debugstr_w( parameter_key_names[entry->hdr.base_key] ),
944 debugstr_w( entry->hdr.regval ));
945 /* fall through */
946 case 0: /* use the default GUI font */
947 GetObjectW( GetStockObject( DEFAULT_GUI_FONT ), sizeof(font), &font );
948 font.lfHeight = map_from_system_dpi( font.lfHeight );
949 font.lfWeight = entry->font.weight;
950 entry->font.val = font;
951 break;
953 get_real_fontname( &entry->font.val, entry->font.fullname );
954 entry->hdr.loaded = TRUE;
956 font = entry->font.val;
957 font.lfHeight = map_to_dpi( font.lfHeight, dpi );
958 lstrcpyW( font.lfFaceName, entry->font.fullname );
959 *(LOGFONTW *)ptr_param = font;
960 return TRUE;
963 /* set a font (binary) parameter in the registry */
964 static BOOL set_font_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
966 LOGFONTW font;
967 WCHAR *ptr;
969 memcpy( &font, ptr_param, sizeof(font) );
970 /* zero pad the end of lfFaceName so we don't save uninitialised data */
971 ptr = wmemchr( font.lfFaceName, 0, LF_FACESIZE );
972 if (ptr) memset( ptr, 0, (font.lfFaceName + LF_FACESIZE - ptr) * sizeof(WCHAR) );
973 if (font.lfHeight < 0) font.lfHeight = map_from_system_dpi( font.lfHeight );
975 if (!save_entry( &entry->hdr, &font, sizeof(font), REG_BINARY, flags )) return FALSE;
976 entry->font.val = font;
977 get_real_fontname( &entry->font.val, entry->font.fullname );
978 entry->hdr.loaded = TRUE;
979 return TRUE;
982 /* initialize a font (binary) parameter */
983 static BOOL init_font_entry( union sysparam_all_entry *entry )
985 GetObjectW( GetStockObject( DEFAULT_GUI_FONT ), sizeof(entry->font.val), &entry->font.val );
986 entry->font.val.lfHeight = map_from_system_dpi( entry->font.val.lfHeight );
987 entry->font.val.lfWeight = entry->font.weight;
988 get_real_fontname( &entry->font.val, entry->font.fullname );
989 return init_entry( &entry->hdr, &entry->font.val, sizeof(entry->font.val), REG_BINARY );
992 /* get a path parameter in the registry */
993 static BOOL get_path_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
995 if (!ptr_param) return FALSE;
997 if (!entry->hdr.loaded)
999 WCHAR buffer[MAX_PATH];
1001 if (load_entry( &entry->hdr, buffer, sizeof(buffer) ))
1002 lstrcpynW( entry->path.path, buffer, MAX_PATH );
1004 lstrcpynW( ptr_param, entry->path.path, int_param );
1005 return TRUE;
1008 /* set a path parameter in the registry */
1009 static BOOL set_path_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
1011 WCHAR buffer[MAX_PATH];
1012 BOOL ret;
1014 lstrcpynW( buffer, ptr_param, MAX_PATH );
1015 ret = save_entry_string( &entry->hdr, buffer, flags );
1016 if (ret)
1018 lstrcpyW( entry->path.path, buffer );
1019 entry->hdr.loaded = TRUE;
1021 return ret;
1024 /* initialize a path parameter */
1025 static BOOL init_path_entry( union sysparam_all_entry *entry )
1027 return init_entry_string( &entry->hdr, entry->path.path );
1030 /* get a binary parameter in the registry */
1031 static BOOL get_binary_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
1033 if (!ptr_param) return FALSE;
1035 if (!entry->hdr.loaded)
1037 void *buffer = HeapAlloc( GetProcessHeap(), 0, entry->bin.size );
1038 DWORD len = load_entry( &entry->hdr, buffer, entry->bin.size );
1040 if (len)
1042 memcpy( entry->bin.ptr, buffer, entry->bin.size );
1043 memset( (char *)entry->bin.ptr + len, 0, entry->bin.size - len );
1045 HeapFree( GetProcessHeap(), 0, buffer );
1047 memcpy( ptr_param, entry->bin.ptr, min( int_param, entry->bin.size ) );
1048 return TRUE;
1051 /* set a binary parameter in the registry */
1052 static BOOL set_binary_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
1054 BOOL ret;
1055 void *buffer = HeapAlloc( GetProcessHeap(), 0, entry->bin.size );
1057 memcpy( buffer, entry->bin.ptr, entry->bin.size );
1058 memcpy( buffer, ptr_param, min( int_param, entry->bin.size ));
1059 ret = save_entry( &entry->hdr, buffer, entry->bin.size, REG_BINARY, flags );
1060 if (ret)
1062 memcpy( entry->bin.ptr, buffer, entry->bin.size );
1063 entry->hdr.loaded = TRUE;
1065 HeapFree( GetProcessHeap(), 0, buffer );
1066 return ret;
1069 /* initialize a binary parameter */
1070 static BOOL init_binary_entry( union sysparam_all_entry *entry )
1072 return init_entry( &entry->hdr, entry->bin.ptr, entry->bin.size, REG_BINARY );
1075 /* get a user pref parameter in the registry */
1076 static BOOL get_userpref_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
1078 union sysparam_all_entry *parent_entry = (union sysparam_all_entry *)entry->pref.parent;
1079 BYTE prefs[8];
1081 if (!ptr_param) return FALSE;
1083 if (!parent_entry->hdr.get( parent_entry, sizeof(prefs), prefs, dpi )) return FALSE;
1084 *(BOOL *)ptr_param = (prefs[entry->pref.offset] & entry->pref.mask) != 0;
1085 return TRUE;
1088 /* set a user pref parameter in the registry */
1089 static BOOL set_userpref_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
1091 union sysparam_all_entry *parent_entry = (union sysparam_all_entry *)entry->pref.parent;
1092 BYTE prefs[8];
1094 parent_entry->hdr.loaded = FALSE; /* force loading it again */
1095 if (!parent_entry->hdr.get( parent_entry, sizeof(prefs), prefs, GetDpiForSystem() )) return FALSE;
1097 if (PtrToUlong( ptr_param )) prefs[entry->pref.offset] |= entry->pref.mask;
1098 else prefs[entry->pref.offset] &= ~entry->pref.mask;
1100 return parent_entry->hdr.set( parent_entry, sizeof(prefs), prefs, flags );
1103 static BOOL get_entry_dpi( void *ptr, UINT int_param, void *ptr_param, UINT dpi )
1105 union sysparam_all_entry *entry = ptr;
1106 return entry->hdr.get( entry, int_param, ptr_param, dpi );
1109 static BOOL get_entry( void *ptr, UINT int_param, void *ptr_param )
1111 return get_entry_dpi( ptr, int_param, ptr_param, GetDpiForSystem() );
1114 static BOOL set_entry( void *ptr, UINT int_param, void *ptr_param, UINT flags )
1116 union sysparam_all_entry *entry = ptr;
1117 return entry->hdr.set( entry, int_param, ptr_param, flags );
1120 #define UINT_ENTRY(name,val,base,reg) \
1121 struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_uint_entry, init_uint_entry, \
1122 base, reg }, (val) }
1124 #define UINT_ENTRY_MIRROR(name,val,base,reg,mirror_base) \
1125 struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_uint_entry, init_uint_entry, \
1126 base, reg, mirror_base, reg }, (val) }
1128 #define INT_ENTRY(name,val,base,reg) \
1129 struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_int_entry, init_int_entry, \
1130 base, reg }, (val) }
1132 #define BOOL_ENTRY(name,val,base,reg) \
1133 struct sysparam_bool_entry entry_##name = { { get_bool_entry, set_bool_entry, init_bool_entry, \
1134 base, reg }, (val) }
1136 #define BOOL_ENTRY_MIRROR(name,val,base,reg,mirror_base) \
1137 struct sysparam_bool_entry entry_##name = { { get_bool_entry, set_bool_entry, init_bool_entry, \
1138 base, reg, mirror_base, reg }, (val) }
1140 #define YESNO_ENTRY(name,val,base,reg) \
1141 struct sysparam_bool_entry entry_##name = { { get_yesno_entry, set_yesno_entry, init_yesno_entry, \
1142 base, reg }, (val) }
1144 #define TWIPS_ENTRY(name,val,base,reg) \
1145 struct sysparam_uint_entry entry_##name = { { get_twips_entry, set_twips_entry, init_int_entry, \
1146 base, reg }, (val) }
1148 #define DWORD_ENTRY(name,val,base,reg) \
1149 struct sysparam_dword_entry entry_##name = { { get_dword_entry, set_dword_entry, init_dword_entry, \
1150 base, reg }, (val) }
1152 #define BINARY_ENTRY(name,data,base,reg) \
1153 struct sysparam_binary_entry entry_##name = { { get_binary_entry, set_binary_entry, init_binary_entry, \
1154 base, reg }, data, sizeof(data) }
1156 #define PATH_ENTRY(name,base,reg) \
1157 struct sysparam_path_entry entry_##name = { { get_path_entry, set_path_entry, init_path_entry, \
1158 base, reg } }
1160 #define FONT_ENTRY(name,weight,base,reg) \
1161 struct sysparam_font_entry entry_##name = { { get_font_entry, set_font_entry, init_font_entry, \
1162 base, reg }, (weight) }
1164 #define USERPREF_ENTRY(name,offset,mask) \
1165 struct sysparam_pref_entry entry_##name = { { get_userpref_entry, set_userpref_entry }, \
1166 &entry_USERPREFERENCESMASK, (offset), (mask) }
1168 static UINT_ENTRY( DRAGWIDTH, 4, DESKTOP_KEY, L"DragWidth" );
1169 static UINT_ENTRY( DRAGHEIGHT, 4, DESKTOP_KEY, L"DragHeight" );
1170 static UINT_ENTRY( DOUBLECLICKTIME, 500, MOUSE_KEY, L"DoubleClickSpeed" );
1171 static UINT_ENTRY( FONTSMOOTHING, 2, DESKTOP_KEY, L"FontSmoothing" );
1172 static UINT_ENTRY( GRIDGRANULARITY, 0, DESKTOP_KEY, L"GridGranularity" );
1173 static UINT_ENTRY( KEYBOARDDELAY, 1, KEYBOARD_KEY, L"KeyboardDelay" );
1174 static UINT_ENTRY( KEYBOARDSPEED, 31, KEYBOARD_KEY, L"KeyboardSpeed" );
1175 static UINT_ENTRY( MENUSHOWDELAY, 400, DESKTOP_KEY, L"MenuShowDelay" );
1176 static UINT_ENTRY( MINARRANGE, ARW_HIDE, METRICS_KEY, L"MinArrange" );
1177 static UINT_ENTRY( MINHORZGAP, 0, METRICS_KEY, L"MinHorzGap" );
1178 static UINT_ENTRY( MINVERTGAP, 0, METRICS_KEY, L"MinVertGap" );
1179 static UINT_ENTRY( MINWIDTH, 154, METRICS_KEY, L"MinWidth" );
1180 static UINT_ENTRY( MOUSEHOVERHEIGHT, 4, MOUSE_KEY, L"MouseHoverHeight" );
1181 static UINT_ENTRY( MOUSEHOVERTIME, 400, MOUSE_KEY, L"MouseHoverTime" );
1182 static UINT_ENTRY( MOUSEHOVERWIDTH, 4, MOUSE_KEY, L"MouseHoverWidth" );
1183 static UINT_ENTRY( MOUSESPEED, 10, MOUSE_KEY, L"MouseSensitivity" );
1184 static UINT_ENTRY( MOUSETRAILS, 0, MOUSE_KEY, L"MouseTrails" );
1185 static UINT_ENTRY( SCREENSAVETIMEOUT, 300, DESKTOP_KEY, L"ScreenSaveTimeOut" );
1186 static UINT_ENTRY( WHEELSCROLLCHARS, 3, DESKTOP_KEY, L"WheelScrollChars" );
1187 static UINT_ENTRY( WHEELSCROLLLINES, 3, DESKTOP_KEY, L"WheelScrollLines" );
1188 static UINT_ENTRY_MIRROR( DOUBLECLKHEIGHT, 4, MOUSE_KEY, L"DoubleClickHeight", DESKTOP_KEY );
1189 static UINT_ENTRY_MIRROR( DOUBLECLKWIDTH, 4, MOUSE_KEY, L"DoubleClickWidth", DESKTOP_KEY );
1190 static UINT_ENTRY_MIRROR( MENUDROPALIGNMENT, 0, DESKTOP_KEY, L"MenuDropAlignment", VERSION_KEY );
1192 static INT_ENTRY( MOUSETHRESHOLD1, 6, MOUSE_KEY, L"MouseThreshold1" );
1193 static INT_ENTRY( MOUSETHRESHOLD2, 10, MOUSE_KEY, L"MouseThreshold2" );
1194 static INT_ENTRY( MOUSEACCELERATION, 1, MOUSE_KEY, L"MouseSpeed" );
1196 static BOOL_ENTRY( BLOCKSENDINPUTRESETS, FALSE, DESKTOP_KEY, L"BlockSendInputResets" );
1197 static BOOL_ENTRY( DRAGFULLWINDOWS, FALSE, DESKTOP_KEY, L"DragFullWindows" );
1198 static BOOL_ENTRY( KEYBOARDPREF, TRUE, KEYBOARDPREF_KEY, L"On" );
1199 static BOOL_ENTRY( LOWPOWERACTIVE, FALSE, DESKTOP_KEY, L"LowPowerActive" );
1200 static BOOL_ENTRY( MOUSEBUTTONSWAP, FALSE, MOUSE_KEY, L"SwapMouseButtons" );
1201 static BOOL_ENTRY( POWEROFFACTIVE, FALSE, DESKTOP_KEY, L"PowerOffActive" );
1202 static BOOL_ENTRY( SCREENREADER, FALSE, SCREENREADER_KEY, L"On" );
1203 static BOOL_ENTRY( SCREENSAVEACTIVE, TRUE, DESKTOP_KEY, L"ScreenSaveActive" );
1204 static BOOL_ENTRY( SCREENSAVERRUNNING, FALSE, DESKTOP_KEY, L"WINE_ScreenSaverRunning" ); /* FIXME - real value */
1205 static BOOL_ENTRY( SHOWSOUNDS, FALSE, SHOWSOUNDS_KEY, L"On" );
1206 static BOOL_ENTRY( SNAPTODEFBUTTON, FALSE, MOUSE_KEY, L"SnapToDefaultButton" );
1207 static BOOL_ENTRY_MIRROR( ICONTITLEWRAP, TRUE, DESKTOP_KEY, L"IconTitleWrap", METRICS_KEY );
1208 static BOOL_ENTRY( AUDIODESC_ON, FALSE, AUDIODESC_KEY, L"On" );
1210 static YESNO_ENTRY( BEEP, TRUE, SOUND_KEY, L"Beep" );
1212 static TWIPS_ENTRY( BORDER, -15, METRICS_KEY, L"BorderWidth" );
1213 static TWIPS_ENTRY( CAPTIONHEIGHT, -270, METRICS_KEY, L"CaptionHeight" );
1214 static TWIPS_ENTRY( CAPTIONWIDTH, -270, METRICS_KEY, L"CaptionWidth" );
1215 static TWIPS_ENTRY( ICONHORIZONTALSPACING, -1125, METRICS_KEY, L"IconSpacing" );
1216 static TWIPS_ENTRY( ICONVERTICALSPACING, -1125, METRICS_KEY, L"IconVerticalSpacing" );
1217 static TWIPS_ENTRY( MENUHEIGHT, -270, METRICS_KEY, L"MenuHeight" );
1218 static TWIPS_ENTRY( MENUWIDTH, -270, METRICS_KEY, L"MenuWidth" );
1219 static TWIPS_ENTRY( PADDEDBORDERWIDTH, 0, METRICS_KEY, L"PaddedBorderWidth" );
1220 static TWIPS_ENTRY( SCROLLHEIGHT, -240, METRICS_KEY, L"ScrollHeight" );
1221 static TWIPS_ENTRY( SCROLLWIDTH, -240, METRICS_KEY, L"ScrollWidth" );
1222 static TWIPS_ENTRY( SMCAPTIONHEIGHT, -225, METRICS_KEY, L"SmCaptionHeight" );
1223 static TWIPS_ENTRY( SMCAPTIONWIDTH, -225, METRICS_KEY, L"SmCaptionWidth" );
1225 static DWORD_ENTRY( ACTIVEWINDOWTRACKING, 0, MOUSE_KEY, L"ActiveWindowTracking" );
1226 static DWORD_ENTRY( ACTIVEWNDTRKTIMEOUT, 0, DESKTOP_KEY, L"ActiveWndTrackTimeout" );
1227 static DWORD_ENTRY( CARETWIDTH, 1, DESKTOP_KEY, L"CaretWidth" );
1228 static DWORD_ENTRY( DPISCALINGVER, 0, DESKTOP_KEY, L"DpiScalingVer" );
1229 static DWORD_ENTRY( FOCUSBORDERHEIGHT, 1, DESKTOP_KEY, L"FocusBorderHeight" );
1230 static DWORD_ENTRY( FOCUSBORDERWIDTH, 1, DESKTOP_KEY, L"FocusBorderWidth" );
1231 static DWORD_ENTRY( FONTSMOOTHINGCONTRAST, 0, DESKTOP_KEY, L"FontSmoothingGamma" );
1232 static DWORD_ENTRY( FONTSMOOTHINGORIENTATION, FE_FONTSMOOTHINGORIENTATIONRGB, DESKTOP_KEY, L"FontSmoothingOrientation" );
1233 static DWORD_ENTRY( FONTSMOOTHINGTYPE, FE_FONTSMOOTHINGSTANDARD, DESKTOP_KEY, L"FontSmoothingType" );
1234 static DWORD_ENTRY( FOREGROUNDFLASHCOUNT, 3, DESKTOP_KEY, L"ForegroundFlashCount" );
1235 static DWORD_ENTRY( FOREGROUNDLOCKTIMEOUT, 0, DESKTOP_KEY, L"ForegroundLockTimeout" );
1236 static DWORD_ENTRY( LOGPIXELS, 0, DESKTOP_KEY, L"LogPixels" );
1237 static DWORD_ENTRY( MOUSECLICKLOCKTIME, 1200, DESKTOP_KEY, L"ClickLockTime" );
1238 static DWORD_ENTRY( AUDIODESC_LOCALE, 0, AUDIODESC_KEY, L"Locale" );
1240 static PATH_ENTRY( DESKPATTERN, DESKTOP_KEY, L"Pattern" );
1241 static PATH_ENTRY( DESKWALLPAPER, DESKTOP_KEY, L"Wallpaper" );
1243 static BYTE user_prefs[8] = { 0x30, 0x00, 0x00, 0x80, 0x12, 0x00, 0x00, 0x00 };
1244 static BINARY_ENTRY( USERPREFERENCESMASK, user_prefs, DESKTOP_KEY, L"UserPreferencesMask" );
1246 static FONT_ENTRY( CAPTIONLOGFONT, FW_BOLD, METRICS_KEY, L"CaptionFont" );
1247 static FONT_ENTRY( ICONTITLELOGFONT, FW_NORMAL, METRICS_KEY, L"IconFont" );
1248 static FONT_ENTRY( MENULOGFONT, FW_NORMAL, METRICS_KEY, L"MenuFont" );
1249 static FONT_ENTRY( MESSAGELOGFONT, FW_NORMAL, METRICS_KEY, L"MessageFont" );
1250 static FONT_ENTRY( SMCAPTIONLOGFONT, FW_NORMAL, METRICS_KEY, L"SmCaptionFont" );
1251 static FONT_ENTRY( STATUSLOGFONT, FW_NORMAL, METRICS_KEY, L"StatusFont" );
1253 static USERPREF_ENTRY( MENUANIMATION, 0, 0x02 );
1254 static USERPREF_ENTRY( COMBOBOXANIMATION, 0, 0x04 );
1255 static USERPREF_ENTRY( LISTBOXSMOOTHSCROLLING, 0, 0x08 );
1256 static USERPREF_ENTRY( GRADIENTCAPTIONS, 0, 0x10 );
1257 static USERPREF_ENTRY( KEYBOARDCUES, 0, 0x20 );
1258 static USERPREF_ENTRY( ACTIVEWNDTRKZORDER, 0, 0x40 );
1259 static USERPREF_ENTRY( HOTTRACKING, 0, 0x80 );
1260 static USERPREF_ENTRY( MENUFADE, 1, 0x02 );
1261 static USERPREF_ENTRY( SELECTIONFADE, 1, 0x04 );
1262 static USERPREF_ENTRY( TOOLTIPANIMATION, 1, 0x08 );
1263 static USERPREF_ENTRY( TOOLTIPFADE, 1, 0x10 );
1264 static USERPREF_ENTRY( CURSORSHADOW, 1, 0x20 );
1265 static USERPREF_ENTRY( MOUSESONAR, 1, 0x40 );
1266 static USERPREF_ENTRY( MOUSECLICKLOCK, 1, 0x80 );
1267 static USERPREF_ENTRY( MOUSEVANISH, 2, 0x01 );
1268 static USERPREF_ENTRY( FLATMENU, 2, 0x02 );
1269 static USERPREF_ENTRY( DROPSHADOW, 2, 0x04 );
1270 static USERPREF_ENTRY( UIEFFECTS, 3, 0x80 );
1271 static USERPREF_ENTRY( DISABLEOVERLAPPEDCONTENT, 4, 0x01 );
1272 static USERPREF_ENTRY( CLIENTAREAANIMATION, 4, 0x02 );
1273 static USERPREF_ENTRY( CLEARTYPE, 4, 0x10 );
1274 static USERPREF_ENTRY( SPEECHRECOGNITION, 4, 0x20 );
1276 static struct sysparam_rgb_entry system_colors[] =
1278 #define RGB_ENTRY(name,val,reg) { { get_rgb_entry, set_rgb_entry, init_rgb_entry, COLORS_KEY, reg }, (val) }
1279 RGB_ENTRY( COLOR_SCROLLBAR, RGB(212, 208, 200), L"Scrollbar" ),
1280 RGB_ENTRY( COLOR_BACKGROUND, RGB(58, 110, 165), L"Background" ),
1281 RGB_ENTRY( COLOR_ACTIVECAPTION, RGB(10, 36, 106), L"ActiveTitle" ),
1282 RGB_ENTRY( COLOR_INACTIVECAPTION, RGB(128, 128, 128), L"InactiveTitle" ),
1283 RGB_ENTRY( COLOR_MENU, RGB(212, 208, 200), L"Menu" ),
1284 RGB_ENTRY( COLOR_WINDOW, RGB(255, 255, 255), L"Window" ),
1285 RGB_ENTRY( COLOR_WINDOWFRAME, RGB(0, 0, 0), L"WindowFrame" ),
1286 RGB_ENTRY( COLOR_MENUTEXT, RGB(0, 0, 0), L"MenuText" ),
1287 RGB_ENTRY( COLOR_WINDOWTEXT, RGB(0, 0, 0), L"WindowText" ),
1288 RGB_ENTRY( COLOR_CAPTIONTEXT, RGB(255, 255, 255), L"TitleText" ),
1289 RGB_ENTRY( COLOR_ACTIVEBORDER, RGB(212, 208, 200), L"ActiveBorder" ),
1290 RGB_ENTRY( COLOR_INACTIVEBORDER, RGB(212, 208, 200), L"InactiveBorder" ),
1291 RGB_ENTRY( COLOR_APPWORKSPACE, RGB(128, 128, 128), L"AppWorkSpace" ),
1292 RGB_ENTRY( COLOR_HIGHLIGHT, RGB(10, 36, 106), L"Hilight" ),
1293 RGB_ENTRY( COLOR_HIGHLIGHTTEXT, RGB(255, 255, 255), L"HilightText" ),
1294 RGB_ENTRY( COLOR_BTNFACE, RGB(212, 208, 200), L"ButtonFace" ),
1295 RGB_ENTRY( COLOR_BTNSHADOW, RGB(128, 128, 128), L"ButtonShadow" ),
1296 RGB_ENTRY( COLOR_GRAYTEXT, RGB(128, 128, 128), L"GrayText" ),
1297 RGB_ENTRY( COLOR_BTNTEXT, RGB(0, 0, 0), L"ButtonText" ),
1298 RGB_ENTRY( COLOR_INACTIVECAPTIONTEXT, RGB(212, 208, 200), L"InactiveTitleText" ),
1299 RGB_ENTRY( COLOR_BTNHIGHLIGHT, RGB(255, 255, 255), L"ButtonHilight" ),
1300 RGB_ENTRY( COLOR_3DDKSHADOW, RGB(64, 64, 64), L"ButtonDkShadow" ),
1301 RGB_ENTRY( COLOR_3DLIGHT, RGB(212, 208, 200), L"ButtonLight" ),
1302 RGB_ENTRY( COLOR_INFOTEXT, RGB(0, 0, 0), L"InfoText" ),
1303 RGB_ENTRY( COLOR_INFOBK, RGB(255, 255, 225), L"InfoWindow" ),
1304 RGB_ENTRY( COLOR_ALTERNATEBTNFACE, RGB(181, 181, 181), L"ButtonAlternateFace" ),
1305 RGB_ENTRY( COLOR_HOTLIGHT, RGB(0, 0, 200), L"HotTrackingColor" ),
1306 RGB_ENTRY( COLOR_GRADIENTACTIVECAPTION, RGB(166, 202, 240), L"GradientActiveTitle" ),
1307 RGB_ENTRY( COLOR_GRADIENTINACTIVECAPTION, RGB(192, 192, 192), L"GradientInactiveTitle" ),
1308 RGB_ENTRY( COLOR_MENUHILIGHT, RGB(10, 36, 106), L"MenuHilight" ),
1309 RGB_ENTRY( COLOR_MENUBAR, RGB(212, 208, 200), L"MenuBar" )
1310 #undef RGB_ENTRY
1313 /* entries that are initialized by default in the registry */
1314 static union sysparam_all_entry * const default_entries[] =
1316 (union sysparam_all_entry *)&entry_ACTIVEWINDOWTRACKING,
1317 (union sysparam_all_entry *)&entry_ACTIVEWNDTRKTIMEOUT,
1318 (union sysparam_all_entry *)&entry_BEEP,
1319 (union sysparam_all_entry *)&entry_BLOCKSENDINPUTRESETS,
1320 (union sysparam_all_entry *)&entry_BORDER,
1321 (union sysparam_all_entry *)&entry_CAPTIONHEIGHT,
1322 (union sysparam_all_entry *)&entry_CAPTIONWIDTH,
1323 (union sysparam_all_entry *)&entry_CARETWIDTH,
1324 (union sysparam_all_entry *)&entry_DESKWALLPAPER,
1325 (union sysparam_all_entry *)&entry_DOUBLECLICKTIME,
1326 (union sysparam_all_entry *)&entry_DOUBLECLKHEIGHT,
1327 (union sysparam_all_entry *)&entry_DOUBLECLKWIDTH,
1328 (union sysparam_all_entry *)&entry_DRAGFULLWINDOWS,
1329 (union sysparam_all_entry *)&entry_DRAGHEIGHT,
1330 (union sysparam_all_entry *)&entry_DRAGWIDTH,
1331 (union sysparam_all_entry *)&entry_FOCUSBORDERHEIGHT,
1332 (union sysparam_all_entry *)&entry_FOCUSBORDERWIDTH,
1333 (union sysparam_all_entry *)&entry_FONTSMOOTHING,
1334 (union sysparam_all_entry *)&entry_FONTSMOOTHINGCONTRAST,
1335 (union sysparam_all_entry *)&entry_FONTSMOOTHINGORIENTATION,
1336 (union sysparam_all_entry *)&entry_FONTSMOOTHINGTYPE,
1337 (union sysparam_all_entry *)&entry_FOREGROUNDFLASHCOUNT,
1338 (union sysparam_all_entry *)&entry_FOREGROUNDLOCKTIMEOUT,
1339 (union sysparam_all_entry *)&entry_ICONHORIZONTALSPACING,
1340 (union sysparam_all_entry *)&entry_ICONTITLEWRAP,
1341 (union sysparam_all_entry *)&entry_ICONVERTICALSPACING,
1342 (union sysparam_all_entry *)&entry_KEYBOARDDELAY,
1343 (union sysparam_all_entry *)&entry_KEYBOARDPREF,
1344 (union sysparam_all_entry *)&entry_KEYBOARDSPEED,
1345 (union sysparam_all_entry *)&entry_LOWPOWERACTIVE,
1346 (union sysparam_all_entry *)&entry_MENUHEIGHT,
1347 (union sysparam_all_entry *)&entry_MENUSHOWDELAY,
1348 (union sysparam_all_entry *)&entry_MENUWIDTH,
1349 (union sysparam_all_entry *)&entry_MOUSEACCELERATION,
1350 (union sysparam_all_entry *)&entry_MOUSEBUTTONSWAP,
1351 (union sysparam_all_entry *)&entry_MOUSECLICKLOCKTIME,
1352 (union sysparam_all_entry *)&entry_MOUSEHOVERHEIGHT,
1353 (union sysparam_all_entry *)&entry_MOUSEHOVERTIME,
1354 (union sysparam_all_entry *)&entry_MOUSEHOVERWIDTH,
1355 (union sysparam_all_entry *)&entry_MOUSESPEED,
1356 (union sysparam_all_entry *)&entry_MOUSETHRESHOLD1,
1357 (union sysparam_all_entry *)&entry_MOUSETHRESHOLD2,
1358 (union sysparam_all_entry *)&entry_PADDEDBORDERWIDTH,
1359 (union sysparam_all_entry *)&entry_SCREENREADER,
1360 (union sysparam_all_entry *)&entry_SCROLLHEIGHT,
1361 (union sysparam_all_entry *)&entry_SCROLLWIDTH,
1362 (union sysparam_all_entry *)&entry_SHOWSOUNDS,
1363 (union sysparam_all_entry *)&entry_SMCAPTIONHEIGHT,
1364 (union sysparam_all_entry *)&entry_SMCAPTIONWIDTH,
1365 (union sysparam_all_entry *)&entry_SNAPTODEFBUTTON,
1366 (union sysparam_all_entry *)&entry_USERPREFERENCESMASK,
1367 (union sysparam_all_entry *)&entry_WHEELSCROLLCHARS,
1368 (union sysparam_all_entry *)&entry_WHEELSCROLLLINES,
1369 (union sysparam_all_entry *)&entry_AUDIODESC_LOCALE,
1370 (union sysparam_all_entry *)&entry_AUDIODESC_ON,
1373 /***********************************************************************
1374 * SYSPARAMS_Init
1376 void SYSPARAMS_Init(void)
1378 HKEY key;
1379 DWORD i, dispos, dpi_scaling;
1381 /* this one must be non-volatile */
1382 if (RegCreateKeyW( HKEY_CURRENT_USER, L"Software\\Wine", &key ))
1384 ERR("Can't create wine registry branch\n");
1385 return;
1388 /* @@ Wine registry key: HKCU\Software\Wine\Temporary System Parameters */
1389 if (RegCreateKeyExW( key, L"Temporary System Parameters", 0, 0,
1390 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, 0, &volatile_base_key, &dispos ))
1391 ERR("Can't create non-permanent wine registry branch\n");
1393 RegCloseKey( key );
1395 get_dword_entry( (union sysparam_all_entry *)&entry_LOGPIXELS, 0, &system_dpi, 0 );
1396 if (!system_dpi) /* check fallback key */
1398 if (!RegOpenKeyW( HKEY_CURRENT_CONFIG, L"Software\\Fonts", &key ))
1400 DWORD type, size = sizeof(system_dpi);
1401 if (RegQueryValueExW( key, L"LogPixels", NULL, &type, (void *)&system_dpi, &size ) ||
1402 type != REG_DWORD)
1403 system_dpi = 0;
1404 RegCloseKey( key );
1407 if (!system_dpi) system_dpi = USER_DEFAULT_SCREEN_DPI;
1409 /* FIXME: what do the DpiScalingVer flags mean? */
1410 get_dword_entry( (union sysparam_all_entry *)&entry_DPISCALINGVER, 0, &dpi_scaling, 0 );
1411 if (!dpi_scaling)
1413 default_awareness = DPI_AWARENESS_PER_MONITOR_AWARE;
1414 dpi_awareness = 0x10 | default_awareness;
1417 if (volatile_base_key && dispos == REG_CREATED_NEW_KEY) /* first process, initialize entries */
1419 for (i = 0; i < ARRAY_SIZE( default_entries ); i++)
1420 default_entries[i]->hdr.init( default_entries[i] );
1424 static BOOL update_desktop_wallpaper(void)
1426 DWORD pid;
1428 if (GetWindowThreadProcessId( GetDesktopWindow(), &pid ) && pid == GetCurrentProcessId())
1430 WCHAR wallpaper[MAX_PATH], pattern[256];
1432 entry_DESKWALLPAPER.hdr.loaded = entry_DESKPATTERN.hdr.loaded = FALSE;
1433 if (get_entry( &entry_DESKWALLPAPER, MAX_PATH, wallpaper ) &&
1434 get_entry( &entry_DESKPATTERN, 256, pattern ))
1435 update_wallpaper( wallpaper, pattern );
1437 else SendMessageW( GetDesktopWindow(), WM_SETTINGCHANGE, SPI_SETDESKWALLPAPER, 0 );
1438 return TRUE;
1442 /***********************************************************************
1443 * SystemParametersInfoForDpi (USER32.@)
1445 BOOL WINAPI SystemParametersInfoForDpi( UINT action, UINT val, PVOID ptr, UINT winini, UINT dpi )
1447 BOOL ret = FALSE;
1449 switch (action)
1451 case SPI_GETICONTITLELOGFONT:
1452 ret = get_entry_dpi( &entry_ICONTITLELOGFONT, val, ptr, dpi );
1453 break;
1454 case SPI_GETNONCLIENTMETRICS:
1456 NONCLIENTMETRICSW *ncm = ptr;
1458 if (!ncm) break;
1459 ret = get_entry_dpi( &entry_BORDER, 0, &ncm->iBorderWidth, dpi ) &&
1460 get_entry_dpi( &entry_SCROLLWIDTH, 0, &ncm->iScrollWidth, dpi ) &&
1461 get_entry_dpi( &entry_SCROLLHEIGHT, 0, &ncm->iScrollHeight, dpi ) &&
1462 get_entry_dpi( &entry_CAPTIONWIDTH, 0, &ncm->iCaptionWidth, dpi ) &&
1463 get_entry_dpi( &entry_CAPTIONHEIGHT, 0, &ncm->iCaptionHeight, dpi ) &&
1464 get_entry_dpi( &entry_CAPTIONLOGFONT, 0, &ncm->lfCaptionFont, dpi ) &&
1465 get_entry_dpi( &entry_SMCAPTIONWIDTH, 0, &ncm->iSmCaptionWidth, dpi ) &&
1466 get_entry_dpi( &entry_SMCAPTIONHEIGHT, 0, &ncm->iSmCaptionHeight, dpi ) &&
1467 get_entry_dpi( &entry_SMCAPTIONLOGFONT, 0, &ncm->lfSmCaptionFont, dpi ) &&
1468 get_entry_dpi( &entry_MENUWIDTH, 0, &ncm->iMenuWidth, dpi ) &&
1469 get_entry_dpi( &entry_MENUHEIGHT, 0, &ncm->iMenuHeight, dpi ) &&
1470 get_entry_dpi( &entry_MENULOGFONT, 0, &ncm->lfMenuFont, dpi ) &&
1471 get_entry_dpi( &entry_STATUSLOGFONT, 0, &ncm->lfStatusFont, dpi ) &&
1472 get_entry_dpi( &entry_MESSAGELOGFONT, 0, &ncm->lfMessageFont, dpi );
1473 if (ret && ncm->cbSize == sizeof(NONCLIENTMETRICSW))
1474 ret = get_entry_dpi( &entry_PADDEDBORDERWIDTH, 0, &ncm->iPaddedBorderWidth, dpi );
1475 normalize_nonclientmetrics( ncm );
1476 break;
1478 case SPI_GETICONMETRICS:
1480 ICONMETRICSW *im = ptr;
1481 if (im && im->cbSize == sizeof(*im))
1482 ret = get_entry_dpi( &entry_ICONHORIZONTALSPACING, 0, &im->iHorzSpacing, dpi ) &&
1483 get_entry_dpi( &entry_ICONVERTICALSPACING, 0, &im->iVertSpacing, dpi ) &&
1484 get_entry_dpi( &entry_ICONTITLEWRAP, 0, &im->iTitleWrap, dpi ) &&
1485 get_entry_dpi( &entry_ICONTITLELOGFONT, 0, &im->lfFont, dpi );
1486 break;
1488 default:
1489 SetLastError( ERROR_INVALID_PARAMETER );
1490 break;
1492 return ret;
1496 /***********************************************************************
1497 * SystemParametersInfoW (USER32.@)
1499 * Each system parameter has flag which shows whether the parameter
1500 * is loaded or not. Parameters, stored directly in SysParametersInfo are
1501 * loaded from registry only when they are requested and the flag is
1502 * "false", after the loading the flag is set to "true". On interprocess
1503 * notification of the parameter change the corresponding parameter flag is
1504 * set to "false". The parameter value will be reloaded when it is requested
1505 * the next time.
1506 * Parameters, backed by or depend on GetSystemMetrics are processed
1507 * differently. These parameters are always loaded. They are reloaded right
1508 * away on interprocess change notification. We can't do lazy loading because
1509 * we don't want to complicate GetSystemMetrics.
1510 * Parameters, backed by X settings are read from corresponding setting.
1511 * On the parameter change request the setting is changed. Interprocess change
1512 * notifications are ignored.
1513 * When parameter value is updated the changed value is stored in permanent
1514 * registry branch if saving is requested. Otherwise it is stored
1515 * in temporary branch
1517 * Some SPI values can also be stored as Twips values in the registry,
1518 * don't forget the conversion!
1520 BOOL WINAPI SystemParametersInfoW( UINT uiAction, UINT uiParam,
1521 PVOID pvParam, UINT fWinIni )
1523 #define WINE_SPI_FIXME(x) \
1524 case x: \
1526 static BOOL warn = TRUE; \
1527 if (warn) \
1529 warn = FALSE; \
1530 FIXME( "Unimplemented action: %u (%s)\n", x, #x ); \
1533 SetLastError( ERROR_INVALID_SPI_VALUE ); \
1534 ret = FALSE; \
1535 break
1536 #define WINE_SPI_WARN(x) \
1537 case x: \
1538 WARN( "Ignored action: %u (%s)\n", x, #x ); \
1539 ret = TRUE; \
1540 break
1542 BOOL ret = USER_Driver->pSystemParametersInfo( uiAction, uiParam, pvParam, fWinIni );
1543 unsigned spi_idx = 0;
1545 if (!ret) switch (uiAction)
1547 case SPI_GETBEEP:
1548 ret = get_entry( &entry_BEEP, uiParam, pvParam );
1549 break;
1550 case SPI_SETBEEP:
1551 ret = set_entry( &entry_BEEP, uiParam, pvParam, fWinIni );
1552 break;
1553 case SPI_GETMOUSE:
1554 ret = get_entry( &entry_MOUSETHRESHOLD1, uiParam, (INT *)pvParam ) &&
1555 get_entry( &entry_MOUSETHRESHOLD2, uiParam, (INT *)pvParam + 1 ) &&
1556 get_entry( &entry_MOUSEACCELERATION, uiParam, (INT *)pvParam + 2 );
1557 break;
1558 case SPI_SETMOUSE:
1559 ret = set_entry( &entry_MOUSETHRESHOLD1, ((INT *)pvParam)[0], pvParam, fWinIni ) &&
1560 set_entry( &entry_MOUSETHRESHOLD2, ((INT *)pvParam)[1], pvParam, fWinIni ) &&
1561 set_entry( &entry_MOUSEACCELERATION, ((INT *)pvParam)[2], pvParam, fWinIni );
1562 break;
1563 case SPI_GETBORDER:
1564 ret = get_entry( &entry_BORDER, uiParam, pvParam );
1565 if (*(INT*)pvParam < 1) *(INT*)pvParam = 1;
1566 break;
1567 case SPI_SETBORDER:
1568 ret = set_entry( &entry_BORDER, uiParam, pvParam, fWinIni );
1569 break;
1570 case SPI_GETKEYBOARDSPEED:
1571 ret = get_entry( &entry_KEYBOARDSPEED, uiParam, pvParam );
1572 break;
1573 case SPI_SETKEYBOARDSPEED:
1574 if (uiParam > 31) uiParam = 31;
1575 ret = set_entry( &entry_KEYBOARDSPEED, uiParam, pvParam, fWinIni );
1576 break;
1578 /* not implemented in Windows */
1579 WINE_SPI_WARN(SPI_LANGDRIVER); /* 12 */
1581 case SPI_ICONHORIZONTALSPACING:
1582 if (pvParam != NULL)
1583 ret = get_entry( &entry_ICONHORIZONTALSPACING, uiParam, pvParam );
1584 else
1586 int min_val = map_to_dpi( 32, GetDpiForSystem() );
1587 ret = set_entry( &entry_ICONHORIZONTALSPACING, max( min_val, uiParam ), pvParam, fWinIni );
1589 break;
1590 case SPI_GETSCREENSAVETIMEOUT:
1591 ret = get_entry( &entry_SCREENSAVETIMEOUT, uiParam, pvParam );
1592 break;
1593 case SPI_SETSCREENSAVETIMEOUT:
1594 ret = set_entry( &entry_SCREENSAVETIMEOUT, uiParam, pvParam, fWinIni );
1595 break;
1596 case SPI_GETSCREENSAVEACTIVE:
1597 ret = get_entry( &entry_SCREENSAVEACTIVE, uiParam, pvParam );
1598 break;
1599 case SPI_SETSCREENSAVEACTIVE:
1600 ret = set_entry( &entry_SCREENSAVEACTIVE, uiParam, pvParam, fWinIni );
1601 break;
1602 case SPI_GETGRIDGRANULARITY:
1603 ret = get_entry( &entry_GRIDGRANULARITY, uiParam, pvParam );
1604 break;
1605 case SPI_SETGRIDGRANULARITY:
1606 ret = set_entry( &entry_GRIDGRANULARITY, uiParam, pvParam, fWinIni );
1607 break;
1608 case SPI_SETDESKWALLPAPER:
1609 if (!pvParam || set_entry( &entry_DESKWALLPAPER, uiParam, pvParam, fWinIni ))
1610 ret = update_desktop_wallpaper();
1611 break;
1612 case SPI_SETDESKPATTERN:
1613 if (!pvParam || set_entry( &entry_DESKPATTERN, uiParam, pvParam, fWinIni ))
1614 ret = update_desktop_wallpaper();
1615 break;
1616 case SPI_GETKEYBOARDDELAY:
1617 ret = get_entry( &entry_KEYBOARDDELAY, uiParam, pvParam );
1618 break;
1619 case SPI_SETKEYBOARDDELAY:
1620 ret = set_entry( &entry_KEYBOARDDELAY, uiParam, pvParam, fWinIni );
1621 break;
1622 case SPI_ICONVERTICALSPACING:
1623 if (pvParam != NULL)
1624 ret = get_entry( &entry_ICONVERTICALSPACING, uiParam, pvParam );
1625 else
1627 int min_val = map_to_dpi( 32, GetDpiForSystem() );
1628 ret = set_entry( &entry_ICONVERTICALSPACING, max( min_val, uiParam ), pvParam, fWinIni );
1630 break;
1631 case SPI_GETICONTITLEWRAP:
1632 ret = get_entry( &entry_ICONTITLEWRAP, uiParam, pvParam );
1633 break;
1634 case SPI_SETICONTITLEWRAP:
1635 ret = set_entry( &entry_ICONTITLEWRAP, uiParam, pvParam, fWinIni );
1636 break;
1637 case SPI_GETMENUDROPALIGNMENT:
1638 ret = get_entry( &entry_MENUDROPALIGNMENT, uiParam, pvParam );
1639 break;
1640 case SPI_SETMENUDROPALIGNMENT:
1641 ret = set_entry( &entry_MENUDROPALIGNMENT, uiParam, pvParam, fWinIni );
1642 break;
1643 case SPI_SETDOUBLECLKWIDTH:
1644 ret = set_entry( &entry_DOUBLECLKWIDTH, uiParam, pvParam, fWinIni );
1645 break;
1646 case SPI_SETDOUBLECLKHEIGHT:
1647 ret = set_entry( &entry_DOUBLECLKHEIGHT, uiParam, pvParam, fWinIni );
1648 break;
1649 case SPI_GETICONTITLELOGFONT:
1650 ret = get_entry( &entry_ICONTITLELOGFONT, uiParam, pvParam );
1651 break;
1652 case SPI_SETDOUBLECLICKTIME:
1653 ret = set_entry( &entry_DOUBLECLICKTIME, uiParam, pvParam, fWinIni );
1654 break;
1655 case SPI_SETMOUSEBUTTONSWAP:
1656 ret = set_entry( &entry_MOUSEBUTTONSWAP, uiParam, pvParam, fWinIni );
1657 break;
1658 case SPI_SETICONTITLELOGFONT:
1659 ret = set_entry( &entry_ICONTITLELOGFONT, uiParam, pvParam, fWinIni );
1660 break;
1662 case SPI_GETFASTTASKSWITCH: /* 35 */
1663 if (!pvParam) return FALSE;
1664 *(BOOL *)pvParam = TRUE;
1665 ret = TRUE;
1666 break;
1668 case SPI_SETFASTTASKSWITCH: /* 36 */
1669 /* the action is disabled */
1670 ret = FALSE;
1671 break;
1673 case SPI_SETDRAGFULLWINDOWS:
1674 ret = set_entry( &entry_DRAGFULLWINDOWS, uiParam, pvParam, fWinIni );
1675 break;
1676 case SPI_GETDRAGFULLWINDOWS:
1677 ret = get_entry( &entry_DRAGFULLWINDOWS, uiParam, pvParam );
1678 break;
1679 case SPI_GETNONCLIENTMETRICS:
1681 LPNONCLIENTMETRICSW lpnm = pvParam;
1682 int padded_border;
1684 if (!pvParam) return FALSE;
1686 ret = get_entry( &entry_BORDER, 0, &lpnm->iBorderWidth ) &&
1687 get_entry( &entry_PADDEDBORDERWIDTH, 0, &padded_border ) &&
1688 get_entry( &entry_SCROLLWIDTH, 0, &lpnm->iScrollWidth ) &&
1689 get_entry( &entry_SCROLLHEIGHT, 0, &lpnm->iScrollHeight ) &&
1690 get_entry( &entry_CAPTIONWIDTH, 0, &lpnm->iCaptionWidth ) &&
1691 get_entry( &entry_CAPTIONHEIGHT, 0, &lpnm->iCaptionHeight ) &&
1692 get_entry( &entry_CAPTIONLOGFONT, 0, &lpnm->lfCaptionFont ) &&
1693 get_entry( &entry_SMCAPTIONWIDTH, 0, &lpnm->iSmCaptionWidth ) &&
1694 get_entry( &entry_SMCAPTIONHEIGHT, 0, &lpnm->iSmCaptionHeight ) &&
1695 get_entry( &entry_SMCAPTIONLOGFONT, 0, &lpnm->lfSmCaptionFont ) &&
1696 get_entry( &entry_MENUWIDTH, 0, &lpnm->iMenuWidth ) &&
1697 get_entry( &entry_MENUHEIGHT, 0, &lpnm->iMenuHeight ) &&
1698 get_entry( &entry_MENULOGFONT, 0, &lpnm->lfMenuFont ) &&
1699 get_entry( &entry_STATUSLOGFONT, 0, &lpnm->lfStatusFont ) &&
1700 get_entry( &entry_MESSAGELOGFONT, 0, &lpnm->lfMessageFont );
1701 if (ret)
1703 lpnm->iBorderWidth += padded_border;
1704 if (lpnm->cbSize == sizeof(NONCLIENTMETRICSW)) lpnm->iPaddedBorderWidth = 0;
1706 normalize_nonclientmetrics( lpnm );
1707 break;
1709 case SPI_SETNONCLIENTMETRICS:
1711 LPNONCLIENTMETRICSW lpnm = pvParam;
1712 int padded_border;
1714 if (lpnm && (lpnm->cbSize == sizeof(NONCLIENTMETRICSW) ||
1715 lpnm->cbSize == FIELD_OFFSET(NONCLIENTMETRICSW, iPaddedBorderWidth)))
1717 get_entry( &entry_PADDEDBORDERWIDTH, 0, &padded_border );
1719 ret = set_entry( &entry_BORDER, lpnm->iBorderWidth - padded_border, NULL, fWinIni ) &&
1720 set_entry( &entry_SCROLLWIDTH, lpnm->iScrollWidth, NULL, fWinIni ) &&
1721 set_entry( &entry_SCROLLHEIGHT, lpnm->iScrollHeight, NULL, fWinIni ) &&
1722 set_entry( &entry_CAPTIONWIDTH, lpnm->iCaptionWidth, NULL, fWinIni ) &&
1723 set_entry( &entry_CAPTIONHEIGHT, lpnm->iCaptionHeight, NULL, fWinIni ) &&
1724 set_entry( &entry_SMCAPTIONWIDTH, lpnm->iSmCaptionWidth, NULL, fWinIni ) &&
1725 set_entry( &entry_SMCAPTIONHEIGHT, lpnm->iSmCaptionHeight, NULL, fWinIni ) &&
1726 set_entry( &entry_MENUWIDTH, lpnm->iMenuWidth, NULL, fWinIni ) &&
1727 set_entry( &entry_MENUHEIGHT, lpnm->iMenuHeight, NULL, fWinIni ) &&
1728 set_entry( &entry_MENULOGFONT, 0, &lpnm->lfMenuFont, fWinIni ) &&
1729 set_entry( &entry_CAPTIONLOGFONT, 0, &lpnm->lfCaptionFont, fWinIni ) &&
1730 set_entry( &entry_SMCAPTIONLOGFONT, 0, &lpnm->lfSmCaptionFont, fWinIni ) &&
1731 set_entry( &entry_STATUSLOGFONT, 0, &lpnm->lfStatusFont, fWinIni ) &&
1732 set_entry( &entry_MESSAGELOGFONT, 0, &lpnm->lfMessageFont, fWinIni );
1734 break;
1736 case SPI_GETMINIMIZEDMETRICS:
1738 MINIMIZEDMETRICS * lpMm = pvParam;
1739 if (lpMm && lpMm->cbSize == sizeof(*lpMm)) {
1740 ret = get_entry( &entry_MINWIDTH, 0, &lpMm->iWidth ) &&
1741 get_entry( &entry_MINHORZGAP, 0, &lpMm->iHorzGap ) &&
1742 get_entry( &entry_MINVERTGAP, 0, &lpMm->iVertGap ) &&
1743 get_entry( &entry_MINARRANGE, 0, &lpMm->iArrange );
1744 lpMm->iWidth = max( 0, lpMm->iWidth );
1745 lpMm->iHorzGap = max( 0, lpMm->iHorzGap );
1746 lpMm->iVertGap = max( 0, lpMm->iVertGap );
1747 lpMm->iArrange &= 0x0f;
1749 break;
1751 case SPI_SETMINIMIZEDMETRICS:
1753 MINIMIZEDMETRICS * lpMm = pvParam;
1754 if (lpMm && lpMm->cbSize == sizeof(*lpMm))
1755 ret = set_entry( &entry_MINWIDTH, max( 0, lpMm->iWidth ), NULL, fWinIni ) &&
1756 set_entry( &entry_MINHORZGAP, max( 0, lpMm->iHorzGap ), NULL, fWinIni ) &&
1757 set_entry( &entry_MINVERTGAP, max( 0, lpMm->iVertGap ), NULL, fWinIni ) &&
1758 set_entry( &entry_MINARRANGE, lpMm->iArrange & 0x0f, NULL, fWinIni );
1759 break;
1761 case SPI_GETICONMETRICS:
1763 LPICONMETRICSW lpIcon = pvParam;
1764 if(lpIcon && lpIcon->cbSize == sizeof(*lpIcon))
1766 ret = get_entry( &entry_ICONHORIZONTALSPACING, 0, &lpIcon->iHorzSpacing ) &&
1767 get_entry( &entry_ICONVERTICALSPACING, 0, &lpIcon->iVertSpacing ) &&
1768 get_entry( &entry_ICONTITLEWRAP, 0, &lpIcon->iTitleWrap ) &&
1769 get_entry( &entry_ICONTITLELOGFONT, 0, &lpIcon->lfFont );
1771 break;
1773 case SPI_SETICONMETRICS:
1775 LPICONMETRICSW lpIcon = pvParam;
1776 if (lpIcon && lpIcon->cbSize == sizeof(*lpIcon))
1777 ret = set_entry( &entry_ICONVERTICALSPACING, max(32,lpIcon->iVertSpacing), NULL, fWinIni ) &&
1778 set_entry( &entry_ICONHORIZONTALSPACING, max(32,lpIcon->iHorzSpacing), NULL, fWinIni ) &&
1779 set_entry( &entry_ICONTITLEWRAP, lpIcon->iTitleWrap, NULL, fWinIni ) &&
1780 set_entry( &entry_ICONTITLELOGFONT, 0, &lpIcon->lfFont, fWinIni );
1781 break;
1784 case SPI_SETWORKAREA: /* 47 WINVER >= 0x400 */
1786 if (!pvParam) return FALSE;
1788 spi_idx = SPI_SETWORKAREA_IDX;
1789 work_area = *(RECT*)pvParam;
1790 spi_loaded[spi_idx] = TRUE;
1791 ret = TRUE;
1792 break;
1795 case SPI_GETWORKAREA: /* 48 WINVER >= 0x400 */
1797 if (!pvParam) return FALSE;
1799 spi_idx = SPI_SETWORKAREA_IDX;
1800 if (!spi_loaded[spi_idx])
1802 SetRect( &work_area, 0, 0,
1803 GetSystemMetrics( SM_CXSCREEN ),
1804 GetSystemMetrics( SM_CYSCREEN ) );
1805 EnumDisplayMonitors( 0, NULL, enum_monitors, (LPARAM)&work_area );
1806 spi_loaded[spi_idx] = TRUE;
1808 *(RECT*)pvParam = work_area;
1809 ret = TRUE;
1810 TRACE("work area %s\n", wine_dbgstr_rect( &work_area ));
1811 break;
1814 WINE_SPI_FIXME(SPI_SETPENWINDOWS); /* 49 WINVER >= 0x400 */
1816 case SPI_GETFILTERKEYS: /* 50 */
1818 LPFILTERKEYS lpFilterKeys = pvParam;
1819 WARN("SPI_GETFILTERKEYS not fully implemented\n");
1820 if (lpFilterKeys && lpFilterKeys->cbSize == sizeof(FILTERKEYS))
1822 /* Indicate that no FilterKeys feature available */
1823 lpFilterKeys->dwFlags = 0;
1824 lpFilterKeys->iWaitMSec = 0;
1825 lpFilterKeys->iDelayMSec = 0;
1826 lpFilterKeys->iRepeatMSec = 0;
1827 lpFilterKeys->iBounceMSec = 0;
1828 ret = TRUE;
1830 break;
1832 WINE_SPI_FIXME(SPI_SETFILTERKEYS); /* 51 */
1834 case SPI_GETTOGGLEKEYS: /* 52 */
1836 LPTOGGLEKEYS lpToggleKeys = pvParam;
1837 WARN("SPI_GETTOGGLEKEYS not fully implemented\n");
1838 if (lpToggleKeys && lpToggleKeys->cbSize == sizeof(TOGGLEKEYS))
1840 /* Indicate that no ToggleKeys feature available */
1841 lpToggleKeys->dwFlags = 0;
1842 ret = TRUE;
1844 break;
1846 WINE_SPI_FIXME(SPI_SETTOGGLEKEYS); /* 53 */
1848 case SPI_GETMOUSEKEYS: /* 54 */
1850 LPMOUSEKEYS lpMouseKeys = pvParam;
1851 WARN("SPI_GETMOUSEKEYS not fully implemented\n");
1852 if (lpMouseKeys && lpMouseKeys->cbSize == sizeof(MOUSEKEYS))
1854 /* Indicate that no MouseKeys feature available */
1855 lpMouseKeys->dwFlags = 0;
1856 lpMouseKeys->iMaxSpeed = 360;
1857 lpMouseKeys->iTimeToMaxSpeed = 1000;
1858 lpMouseKeys->iCtrlSpeed = 0;
1859 lpMouseKeys->dwReserved1 = 0;
1860 lpMouseKeys->dwReserved2 = 0;
1861 ret = TRUE;
1863 break;
1865 WINE_SPI_FIXME(SPI_SETMOUSEKEYS); /* 55 */
1867 case SPI_GETSHOWSOUNDS:
1868 ret = get_entry( &entry_SHOWSOUNDS, uiParam, pvParam );
1869 break;
1870 case SPI_SETSHOWSOUNDS:
1871 ret = set_entry( &entry_SHOWSOUNDS, uiParam, pvParam, fWinIni );
1872 break;
1874 case SPI_GETSTICKYKEYS: /* 58 */
1876 LPSTICKYKEYS lpStickyKeys = pvParam;
1877 WARN("SPI_GETSTICKYKEYS not fully implemented\n");
1878 if (lpStickyKeys && lpStickyKeys->cbSize == sizeof(STICKYKEYS))
1880 /* Indicate that no StickyKeys feature available */
1881 lpStickyKeys->dwFlags = 0;
1882 ret = TRUE;
1884 break;
1886 WINE_SPI_FIXME(SPI_SETSTICKYKEYS); /* 59 */
1888 case SPI_GETACCESSTIMEOUT: /* 60 */
1890 LPACCESSTIMEOUT lpAccessTimeout = pvParam;
1891 WARN("SPI_GETACCESSTIMEOUT not fully implemented\n");
1892 if (lpAccessTimeout && lpAccessTimeout->cbSize == sizeof(ACCESSTIMEOUT))
1894 /* Indicate that no accessibility features timeout is available */
1895 lpAccessTimeout->dwFlags = 0;
1896 lpAccessTimeout->iTimeOutMSec = 0;
1897 ret = TRUE;
1899 break;
1901 WINE_SPI_FIXME(SPI_SETACCESSTIMEOUT); /* 61 */
1903 case SPI_GETSERIALKEYS: /* 62 WINVER >= 0x400 */
1905 LPSERIALKEYSW lpSerialKeysW = pvParam;
1906 WARN("SPI_GETSERIALKEYS not fully implemented\n");
1907 if (lpSerialKeysW && lpSerialKeysW->cbSize == sizeof(SERIALKEYSW))
1909 /* Indicate that no SerialKeys feature available */
1910 lpSerialKeysW->dwFlags = 0;
1911 lpSerialKeysW->lpszActivePort = NULL;
1912 lpSerialKeysW->lpszPort = NULL;
1913 lpSerialKeysW->iBaudRate = 0;
1914 lpSerialKeysW->iPortState = 0;
1915 ret = TRUE;
1917 break;
1919 WINE_SPI_FIXME(SPI_SETSERIALKEYS); /* 63 WINVER >= 0x400 */
1921 case SPI_GETSOUNDSENTRY: /* 64 */
1923 LPSOUNDSENTRYW lpSoundSentryW = pvParam;
1924 WARN("SPI_GETSOUNDSENTRY not fully implemented\n");
1925 if (lpSoundSentryW && lpSoundSentryW->cbSize == sizeof(SOUNDSENTRYW))
1927 /* Indicate that no SoundSentry feature available */
1928 lpSoundSentryW->dwFlags = 0;
1929 lpSoundSentryW->iFSTextEffect = 0;
1930 lpSoundSentryW->iFSTextEffectMSec = 0;
1931 lpSoundSentryW->iFSTextEffectColorBits = 0;
1932 lpSoundSentryW->iFSGrafEffect = 0;
1933 lpSoundSentryW->iFSGrafEffectMSec = 0;
1934 lpSoundSentryW->iFSGrafEffectColor = 0;
1935 lpSoundSentryW->iWindowsEffect = 0;
1936 lpSoundSentryW->iWindowsEffectMSec = 0;
1937 lpSoundSentryW->lpszWindowsEffectDLL = 0;
1938 lpSoundSentryW->iWindowsEffectOrdinal = 0;
1939 ret = TRUE;
1941 break;
1943 WINE_SPI_FIXME(SPI_SETSOUNDSENTRY); /* 65 */
1945 case SPI_GETHIGHCONTRAST: /* 66 WINVER >= 0x400 */
1947 LPHIGHCONTRASTW lpHighContrastW = pvParam;
1948 WARN("SPI_GETHIGHCONTRAST not fully implemented\n");
1949 if (lpHighContrastW && lpHighContrastW->cbSize == sizeof(HIGHCONTRASTW))
1951 /* Indicate that no high contrast feature available */
1952 lpHighContrastW->dwFlags = 0;
1953 lpHighContrastW->lpszDefaultScheme = NULL;
1954 ret = TRUE;
1956 break;
1958 WINE_SPI_FIXME(SPI_SETHIGHCONTRAST); /* 67 WINVER >= 0x400 */
1960 case SPI_GETKEYBOARDPREF:
1961 ret = get_entry( &entry_KEYBOARDPREF, uiParam, pvParam );
1962 break;
1963 case SPI_SETKEYBOARDPREF:
1964 ret = set_entry( &entry_KEYBOARDPREF, uiParam, pvParam, fWinIni );
1965 break;
1966 case SPI_GETSCREENREADER:
1967 ret = get_entry( &entry_SCREENREADER, uiParam, pvParam );
1968 break;
1969 case SPI_SETSCREENREADER:
1970 ret = set_entry( &entry_SCREENREADER, uiParam, pvParam, fWinIni );
1971 break;
1973 case SPI_GETANIMATION: /* 72 WINVER >= 0x400 */
1975 LPANIMATIONINFO lpAnimInfo = pvParam;
1977 /* Tell it "disabled" */
1978 if (lpAnimInfo && lpAnimInfo->cbSize == sizeof(ANIMATIONINFO))
1980 lpAnimInfo->iMinAnimate = 0; /* Minimize and restore animation is disabled (nonzero == enabled) */
1981 ret = TRUE;
1983 break;
1985 WINE_SPI_WARN(SPI_SETANIMATION); /* 73 WINVER >= 0x400 */
1987 case SPI_GETFONTSMOOTHING:
1988 ret = get_entry( &entry_FONTSMOOTHING, uiParam, pvParam );
1989 if (ret) *(UINT *)pvParam = (*(UINT *)pvParam != 0);
1990 break;
1991 case SPI_SETFONTSMOOTHING:
1992 uiParam = uiParam ? 2 : 0; /* Win NT4/2k/XP behavior */
1993 ret = set_entry( &entry_FONTSMOOTHING, uiParam, pvParam, fWinIni );
1994 break;
1995 case SPI_SETDRAGWIDTH:
1996 ret = set_entry( &entry_DRAGWIDTH, uiParam, pvParam, fWinIni );
1997 break;
1998 case SPI_SETDRAGHEIGHT:
1999 ret = set_entry( &entry_DRAGHEIGHT, uiParam, pvParam, fWinIni );
2000 break;
2002 WINE_SPI_FIXME(SPI_SETHANDHELD); /* 78 WINVER >= 0x400 */
2004 WINE_SPI_FIXME(SPI_GETLOWPOWERTIMEOUT); /* 79 WINVER >= 0x400 */
2005 WINE_SPI_FIXME(SPI_GETPOWEROFFTIMEOUT); /* 80 WINVER >= 0x400 */
2006 WINE_SPI_FIXME(SPI_SETLOWPOWERTIMEOUT); /* 81 WINVER >= 0x400 */
2007 WINE_SPI_FIXME(SPI_SETPOWEROFFTIMEOUT); /* 82 WINVER >= 0x400 */
2009 case SPI_GETLOWPOWERACTIVE:
2010 ret = get_entry( &entry_LOWPOWERACTIVE, uiParam, pvParam );
2011 break;
2012 case SPI_SETLOWPOWERACTIVE:
2013 ret = set_entry( &entry_LOWPOWERACTIVE, uiParam, pvParam, fWinIni );
2014 break;
2015 case SPI_GETPOWEROFFACTIVE:
2016 ret = get_entry( &entry_POWEROFFACTIVE, uiParam, pvParam );
2017 break;
2018 case SPI_SETPOWEROFFACTIVE:
2019 ret = set_entry( &entry_POWEROFFACTIVE, uiParam, pvParam, fWinIni );
2020 break;
2022 WINE_SPI_FIXME(SPI_SETCURSORS); /* 87 WINVER >= 0x400 */
2023 WINE_SPI_FIXME(SPI_SETICONS); /* 88 WINVER >= 0x400 */
2025 case SPI_GETDEFAULTINPUTLANG: /* 89 WINVER >= 0x400 */
2026 ret = GetKeyboardLayout(0) != 0;
2027 break;
2029 WINE_SPI_FIXME(SPI_SETDEFAULTINPUTLANG); /* 90 WINVER >= 0x400 */
2031 WINE_SPI_FIXME(SPI_SETLANGTOGGLE); /* 91 WINVER >= 0x400 */
2033 case SPI_GETWINDOWSEXTENSION: /* 92 WINVER >= 0x400 */
2034 WARN("pretend no support for Win9x Plus! for now.\n");
2035 ret = FALSE; /* yes, this is the result value */
2036 break;
2037 case SPI_SETMOUSETRAILS:
2038 ret = set_entry( &entry_MOUSETRAILS, uiParam, pvParam, fWinIni );
2039 break;
2040 case SPI_GETMOUSETRAILS:
2041 ret = get_entry( &entry_MOUSETRAILS, uiParam, pvParam );
2042 break;
2043 case SPI_GETSNAPTODEFBUTTON:
2044 ret = get_entry( &entry_SNAPTODEFBUTTON, uiParam, pvParam );
2045 break;
2046 case SPI_SETSNAPTODEFBUTTON:
2047 ret = set_entry( &entry_SNAPTODEFBUTTON, uiParam, pvParam, fWinIni );
2048 break;
2049 case SPI_SETSCREENSAVERRUNNING:
2050 ret = set_entry( &entry_SCREENSAVERRUNNING, uiParam, pvParam, fWinIni );
2051 break;
2052 case SPI_GETMOUSEHOVERWIDTH:
2053 ret = get_entry( &entry_MOUSEHOVERWIDTH, uiParam, pvParam );
2054 break;
2055 case SPI_SETMOUSEHOVERWIDTH:
2056 ret = set_entry( &entry_MOUSEHOVERWIDTH, uiParam, pvParam, fWinIni );
2057 break;
2058 case SPI_GETMOUSEHOVERHEIGHT:
2059 ret = get_entry( &entry_MOUSEHOVERHEIGHT, uiParam, pvParam );
2060 break;
2061 case SPI_SETMOUSEHOVERHEIGHT:
2062 ret = set_entry( &entry_MOUSEHOVERHEIGHT, uiParam, pvParam, fWinIni );
2063 break;
2064 case SPI_GETMOUSEHOVERTIME:
2065 ret = get_entry( &entry_MOUSEHOVERTIME, uiParam, pvParam );
2066 break;
2067 case SPI_SETMOUSEHOVERTIME:
2068 ret = set_entry( &entry_MOUSEHOVERTIME, uiParam, pvParam, fWinIni );
2069 break;
2070 case SPI_GETWHEELSCROLLLINES:
2071 ret = get_entry( &entry_WHEELSCROLLLINES, uiParam, pvParam );
2072 break;
2073 case SPI_SETWHEELSCROLLLINES:
2074 ret = set_entry( &entry_WHEELSCROLLLINES, uiParam, pvParam, fWinIni );
2075 break;
2076 case SPI_GETMENUSHOWDELAY:
2077 ret = get_entry( &entry_MENUSHOWDELAY, uiParam, pvParam );
2078 break;
2079 case SPI_SETMENUSHOWDELAY:
2080 ret = set_entry( &entry_MENUSHOWDELAY, uiParam, pvParam, fWinIni );
2081 break;
2082 case SPI_GETWHEELSCROLLCHARS:
2083 ret = get_entry( &entry_WHEELSCROLLCHARS, uiParam, pvParam );
2084 break;
2085 case SPI_SETWHEELSCROLLCHARS:
2086 ret = set_entry( &entry_WHEELSCROLLCHARS, uiParam, pvParam, fWinIni );
2087 break;
2089 WINE_SPI_FIXME(SPI_GETSHOWIMEUI); /* 110 _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
2090 WINE_SPI_FIXME(SPI_SETSHOWIMEUI); /* 111 _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
2092 case SPI_GETMOUSESPEED:
2093 ret = get_entry( &entry_MOUSESPEED, uiParam, pvParam );
2094 break;
2095 case SPI_SETMOUSESPEED:
2096 ret = set_entry( &entry_MOUSESPEED, uiParam, pvParam, fWinIni );
2097 break;
2098 case SPI_GETSCREENSAVERRUNNING:
2099 ret = get_entry( &entry_SCREENSAVERRUNNING, uiParam, pvParam );
2100 break;
2101 case SPI_GETDESKWALLPAPER:
2102 ret = get_entry( &entry_DESKWALLPAPER, uiParam, pvParam );
2103 break;
2104 case SPI_GETACTIVEWINDOWTRACKING:
2105 ret = get_entry( &entry_ACTIVEWINDOWTRACKING, uiParam, pvParam );
2106 break;
2107 case SPI_SETACTIVEWINDOWTRACKING:
2108 ret = set_entry( &entry_ACTIVEWINDOWTRACKING, uiParam, pvParam, fWinIni );
2109 break;
2110 case SPI_GETMENUANIMATION:
2111 ret = get_entry( &entry_MENUANIMATION, uiParam, pvParam );
2112 break;
2113 case SPI_SETMENUANIMATION:
2114 ret = set_entry( &entry_MENUANIMATION, uiParam, pvParam, fWinIni );
2115 break;
2116 case SPI_GETCOMBOBOXANIMATION:
2117 ret = get_entry( &entry_COMBOBOXANIMATION, uiParam, pvParam );
2118 break;
2119 case SPI_SETCOMBOBOXANIMATION:
2120 ret = set_entry( &entry_COMBOBOXANIMATION, uiParam, pvParam, fWinIni );
2121 break;
2122 case SPI_GETLISTBOXSMOOTHSCROLLING:
2123 ret = get_entry( &entry_LISTBOXSMOOTHSCROLLING, uiParam, pvParam );
2124 break;
2125 case SPI_SETLISTBOXSMOOTHSCROLLING:
2126 ret = set_entry( &entry_LISTBOXSMOOTHSCROLLING, uiParam, pvParam, fWinIni );
2127 break;
2128 case SPI_GETGRADIENTCAPTIONS:
2129 ret = get_entry( &entry_GRADIENTCAPTIONS, uiParam, pvParam );
2130 break;
2131 case SPI_SETGRADIENTCAPTIONS:
2132 ret = set_entry( &entry_GRADIENTCAPTIONS, uiParam, pvParam, fWinIni );
2133 break;
2134 case SPI_GETKEYBOARDCUES:
2135 ret = get_entry( &entry_KEYBOARDCUES, uiParam, pvParam );
2136 break;
2137 case SPI_SETKEYBOARDCUES:
2138 ret = set_entry( &entry_KEYBOARDCUES, uiParam, pvParam, fWinIni );
2139 break;
2140 case SPI_GETACTIVEWNDTRKZORDER:
2141 ret = get_entry( &entry_ACTIVEWNDTRKZORDER, uiParam, pvParam );
2142 break;
2143 case SPI_SETACTIVEWNDTRKZORDER:
2144 ret = set_entry( &entry_ACTIVEWNDTRKZORDER, uiParam, pvParam, fWinIni );
2145 break;
2146 case SPI_GETHOTTRACKING:
2147 ret = get_entry( &entry_HOTTRACKING, uiParam, pvParam );
2148 break;
2149 case SPI_SETHOTTRACKING:
2150 ret = set_entry( &entry_HOTTRACKING, uiParam, pvParam, fWinIni );
2151 break;
2152 case SPI_GETMENUFADE:
2153 ret = get_entry( &entry_MENUFADE, uiParam, pvParam );
2154 break;
2155 case SPI_SETMENUFADE:
2156 ret = set_entry( &entry_MENUFADE, uiParam, pvParam, fWinIni );
2157 break;
2158 case SPI_GETSELECTIONFADE:
2159 ret = get_entry( &entry_SELECTIONFADE, uiParam, pvParam );
2160 break;
2161 case SPI_SETSELECTIONFADE:
2162 ret = set_entry( &entry_SELECTIONFADE, uiParam, pvParam, fWinIni );
2163 break;
2164 case SPI_GETTOOLTIPANIMATION:
2165 ret = get_entry( &entry_TOOLTIPANIMATION, uiParam, pvParam );
2166 break;
2167 case SPI_SETTOOLTIPANIMATION:
2168 ret = set_entry( &entry_TOOLTIPANIMATION, uiParam, pvParam, fWinIni );
2169 break;
2170 case SPI_GETTOOLTIPFADE:
2171 ret = get_entry( &entry_TOOLTIPFADE, uiParam, pvParam );
2172 break;
2173 case SPI_SETTOOLTIPFADE:
2174 ret = set_entry( &entry_TOOLTIPFADE, uiParam, pvParam, fWinIni );
2175 break;
2176 case SPI_GETCURSORSHADOW:
2177 ret = get_entry( &entry_CURSORSHADOW, uiParam, pvParam );
2178 break;
2179 case SPI_SETCURSORSHADOW:
2180 ret = set_entry( &entry_CURSORSHADOW, uiParam, pvParam, fWinIni );
2181 break;
2182 case SPI_GETMOUSESONAR:
2183 ret = get_entry( &entry_MOUSESONAR, uiParam, pvParam );
2184 break;
2185 case SPI_SETMOUSESONAR:
2186 ret = set_entry( &entry_MOUSESONAR, uiParam, pvParam, fWinIni );
2187 break;
2188 case SPI_GETMOUSECLICKLOCK:
2189 ret = get_entry( &entry_MOUSECLICKLOCK, uiParam, pvParam );
2190 break;
2191 case SPI_SETMOUSECLICKLOCK:
2192 ret = set_entry( &entry_MOUSECLICKLOCK, uiParam, pvParam, fWinIni );
2193 break;
2194 case SPI_GETMOUSEVANISH:
2195 ret = get_entry( &entry_MOUSEVANISH, uiParam, pvParam );
2196 break;
2197 case SPI_SETMOUSEVANISH:
2198 ret = set_entry( &entry_MOUSEVANISH, uiParam, pvParam, fWinIni );
2199 break;
2200 case SPI_GETFLATMENU:
2201 ret = get_entry( &entry_FLATMENU, uiParam, pvParam );
2202 break;
2203 case SPI_SETFLATMENU:
2204 ret = set_entry( &entry_FLATMENU, uiParam, pvParam, fWinIni );
2205 break;
2206 case SPI_GETDROPSHADOW:
2207 ret = get_entry( &entry_DROPSHADOW, uiParam, pvParam );
2208 break;
2209 case SPI_SETDROPSHADOW:
2210 ret = set_entry( &entry_DROPSHADOW, uiParam, pvParam, fWinIni );
2211 break;
2212 case SPI_GETBLOCKSENDINPUTRESETS:
2213 ret = get_entry( &entry_BLOCKSENDINPUTRESETS, uiParam, pvParam );
2214 break;
2215 case SPI_SETBLOCKSENDINPUTRESETS:
2216 ret = set_entry( &entry_BLOCKSENDINPUTRESETS, uiParam, pvParam, fWinIni );
2217 break;
2218 case SPI_GETUIEFFECTS:
2219 ret = get_entry( &entry_UIEFFECTS, uiParam, pvParam );
2220 break;
2221 case SPI_SETUIEFFECTS:
2222 /* FIXME: this probably should mask other UI effect values when unset */
2223 ret = set_entry( &entry_UIEFFECTS, uiParam, pvParam, fWinIni );
2224 break;
2225 case SPI_GETDISABLEOVERLAPPEDCONTENT:
2226 ret = get_entry( &entry_DISABLEOVERLAPPEDCONTENT, uiParam, pvParam );
2227 break;
2228 case SPI_SETDISABLEOVERLAPPEDCONTENT:
2229 ret = set_entry( &entry_DISABLEOVERLAPPEDCONTENT, uiParam, pvParam, fWinIni );
2230 break;
2231 case SPI_GETCLIENTAREAANIMATION:
2232 ret = get_entry( &entry_CLIENTAREAANIMATION, uiParam, pvParam );
2233 break;
2234 case SPI_SETCLIENTAREAANIMATION:
2235 ret = set_entry( &entry_CLIENTAREAANIMATION, uiParam, pvParam, fWinIni );
2236 break;
2237 case SPI_GETCLEARTYPE:
2238 ret = get_entry( &entry_CLEARTYPE, uiParam, pvParam );
2239 break;
2240 case SPI_SETCLEARTYPE:
2241 ret = set_entry( &entry_CLEARTYPE, uiParam, pvParam, fWinIni );
2242 break;
2243 case SPI_GETSPEECHRECOGNITION:
2244 ret = get_entry( &entry_SPEECHRECOGNITION, uiParam, pvParam );
2245 break;
2246 case SPI_SETSPEECHRECOGNITION:
2247 ret = set_entry( &entry_SPEECHRECOGNITION, uiParam, pvParam, fWinIni );
2248 break;
2249 case SPI_GETFOREGROUNDLOCKTIMEOUT:
2250 ret = get_entry( &entry_FOREGROUNDLOCKTIMEOUT, uiParam, pvParam );
2251 break;
2252 case SPI_SETFOREGROUNDLOCKTIMEOUT:
2253 /* FIXME: this should check that the calling thread
2254 * is able to change the foreground window */
2255 ret = set_entry( &entry_FOREGROUNDLOCKTIMEOUT, uiParam, pvParam, fWinIni );
2256 break;
2257 case SPI_GETACTIVEWNDTRKTIMEOUT:
2258 ret = get_entry( &entry_ACTIVEWNDTRKTIMEOUT, uiParam, pvParam );
2259 break;
2260 case SPI_SETACTIVEWNDTRKTIMEOUT:
2261 ret = get_entry( &entry_ACTIVEWNDTRKTIMEOUT, uiParam, pvParam );
2262 break;
2263 case SPI_GETFOREGROUNDFLASHCOUNT:
2264 ret = get_entry( &entry_FOREGROUNDFLASHCOUNT, uiParam, pvParam );
2265 break;
2266 case SPI_SETFOREGROUNDFLASHCOUNT:
2267 ret = set_entry( &entry_FOREGROUNDFLASHCOUNT, uiParam, pvParam, fWinIni );
2268 break;
2269 case SPI_GETCARETWIDTH:
2270 ret = get_entry( &entry_CARETWIDTH, uiParam, pvParam );
2271 break;
2272 case SPI_SETCARETWIDTH:
2273 ret = set_entry( &entry_CARETWIDTH, uiParam, pvParam, fWinIni );
2274 break;
2275 case SPI_GETMOUSECLICKLOCKTIME:
2276 ret = get_entry( &entry_MOUSECLICKLOCKTIME, uiParam, pvParam );
2277 break;
2278 case SPI_SETMOUSECLICKLOCKTIME:
2279 ret = set_entry( &entry_MOUSECLICKLOCKTIME, uiParam, pvParam, fWinIni );
2280 break;
2281 case SPI_GETFONTSMOOTHINGTYPE:
2282 ret = get_entry( &entry_FONTSMOOTHINGTYPE, uiParam, pvParam );
2283 break;
2284 case SPI_SETFONTSMOOTHINGTYPE:
2285 ret = set_entry( &entry_FONTSMOOTHINGTYPE, uiParam, pvParam, fWinIni );
2286 break;
2287 case SPI_GETFONTSMOOTHINGCONTRAST:
2288 ret = get_entry( &entry_FONTSMOOTHINGCONTRAST, uiParam, pvParam );
2289 break;
2290 case SPI_SETFONTSMOOTHINGCONTRAST:
2291 ret = set_entry( &entry_FONTSMOOTHINGCONTRAST, uiParam, pvParam, fWinIni );
2292 break;
2293 case SPI_GETFOCUSBORDERWIDTH:
2294 ret = get_entry( &entry_FOCUSBORDERWIDTH, uiParam, pvParam );
2295 break;
2296 case SPI_GETFOCUSBORDERHEIGHT:
2297 ret = get_entry( &entry_FOCUSBORDERHEIGHT, uiParam, pvParam );
2298 break;
2299 case SPI_SETFOCUSBORDERWIDTH:
2300 ret = set_entry( &entry_FOCUSBORDERWIDTH, uiParam, pvParam, fWinIni );
2301 break;
2302 case SPI_SETFOCUSBORDERHEIGHT:
2303 ret = set_entry( &entry_FOCUSBORDERHEIGHT, uiParam, pvParam, fWinIni );
2304 break;
2305 case SPI_GETFONTSMOOTHINGORIENTATION:
2306 ret = get_entry( &entry_FONTSMOOTHINGORIENTATION, uiParam, pvParam );
2307 break;
2308 case SPI_SETFONTSMOOTHINGORIENTATION:
2309 ret = set_entry( &entry_FONTSMOOTHINGORIENTATION, uiParam, pvParam, fWinIni );
2310 break;
2311 case SPI_GETAUDIODESCRIPTION:
2313 AUDIODESCRIPTION *audio = pvParam;
2314 if (audio && audio->cbSize == sizeof(AUDIODESCRIPTION) && uiParam == sizeof(AUDIODESCRIPTION) )
2316 ret = get_entry( &entry_AUDIODESC_ON, 0, &audio->Enabled ) &&
2317 get_entry( &entry_AUDIODESC_LOCALE, 0, &audio->Locale );
2319 break;
2321 case SPI_SETAUDIODESCRIPTION:
2323 AUDIODESCRIPTION *audio = pvParam;
2324 if (audio && audio->cbSize == sizeof(AUDIODESCRIPTION) && uiParam == sizeof(AUDIODESCRIPTION) )
2326 ret = set_entry( &entry_AUDIODESC_ON, 0, &audio->Enabled, fWinIni) &&
2327 set_entry( &entry_AUDIODESC_LOCALE, 0, &audio->Locale, fWinIni );
2329 break;
2331 default:
2332 FIXME( "Unknown action: %u\n", uiAction );
2333 SetLastError( ERROR_INVALID_SPI_VALUE );
2334 ret = FALSE;
2335 break;
2338 if (ret)
2339 SYSPARAMS_NotifyChange( uiAction, fWinIni );
2340 TRACE("(%u, %u, %p, %u) ret %d\n",
2341 uiAction, uiParam, pvParam, fWinIni, ret);
2342 return ret;
2344 #undef WINE_SPI_FIXME
2345 #undef WINE_SPI_WARN
2349 /***********************************************************************
2350 * SystemParametersInfoA (USER32.@)
2352 BOOL WINAPI SystemParametersInfoA( UINT uiAction, UINT uiParam,
2353 PVOID pvParam, UINT fuWinIni )
2355 BOOL ret;
2357 TRACE("(%u, %u, %p, %u)\n", uiAction, uiParam, pvParam, fuWinIni);
2359 switch (uiAction)
2361 case SPI_SETDESKWALLPAPER: /* 20 */
2362 case SPI_SETDESKPATTERN: /* 21 */
2364 WCHAR buffer[256];
2365 if (pvParam)
2366 if (!MultiByteToWideChar( CP_ACP, 0, pvParam, -1, buffer, ARRAY_SIZE( buffer )))
2367 buffer[ARRAY_SIZE(buffer)-1] = 0;
2368 ret = SystemParametersInfoW( uiAction, uiParam, pvParam ? buffer : NULL, fuWinIni );
2369 break;
2372 case SPI_GETICONTITLELOGFONT: /* 31 */
2374 LOGFONTW tmp;
2375 ret = SystemParametersInfoW( uiAction, uiParam, pvParam ? &tmp : NULL, fuWinIni );
2376 if (ret && pvParam)
2377 SYSPARAMS_LogFont32WTo32A( &tmp, pvParam );
2378 break;
2381 case SPI_GETNONCLIENTMETRICS: /* 41 WINVER >= 0x400 */
2383 NONCLIENTMETRICSW tmp;
2384 LPNONCLIENTMETRICSA lpnmA = pvParam;
2385 if (lpnmA && (lpnmA->cbSize == sizeof(NONCLIENTMETRICSA) ||
2386 lpnmA->cbSize == FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth)))
2388 tmp.cbSize = sizeof(NONCLIENTMETRICSW);
2389 ret = SystemParametersInfoW( uiAction, uiParam, &tmp, fuWinIni );
2390 if (ret)
2391 SYSPARAMS_NonClientMetrics32WTo32A( &tmp, lpnmA );
2393 else
2394 ret = FALSE;
2395 break;
2398 case SPI_SETNONCLIENTMETRICS: /* 42 WINVER >= 0x400 */
2400 NONCLIENTMETRICSW tmp;
2401 LPNONCLIENTMETRICSA lpnmA = pvParam;
2402 if (lpnmA && (lpnmA->cbSize == sizeof(NONCLIENTMETRICSA) ||
2403 lpnmA->cbSize == FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth)))
2405 tmp.cbSize = sizeof(NONCLIENTMETRICSW);
2406 SYSPARAMS_NonClientMetrics32ATo32W( lpnmA, &tmp );
2407 ret = SystemParametersInfoW( uiAction, uiParam, &tmp, fuWinIni );
2409 else
2410 ret = FALSE;
2411 break;
2414 case SPI_GETICONMETRICS: /* 45 WINVER >= 0x400 */
2416 ICONMETRICSW tmp;
2417 LPICONMETRICSA lpimA = pvParam;
2418 if (lpimA && lpimA->cbSize == sizeof(ICONMETRICSA))
2420 tmp.cbSize = sizeof(ICONMETRICSW);
2421 ret = SystemParametersInfoW( uiAction, uiParam, &tmp, fuWinIni );
2422 if (ret)
2424 lpimA->iHorzSpacing = tmp.iHorzSpacing;
2425 lpimA->iVertSpacing = tmp.iVertSpacing;
2426 lpimA->iTitleWrap = tmp.iTitleWrap;
2427 SYSPARAMS_LogFont32WTo32A( &tmp.lfFont, &lpimA->lfFont );
2430 else
2431 ret = FALSE;
2432 break;
2435 case SPI_SETICONMETRICS: /* 46 WINVER >= 0x400 */
2437 ICONMETRICSW tmp;
2438 LPICONMETRICSA lpimA = pvParam;
2439 if (lpimA && lpimA->cbSize == sizeof(ICONMETRICSA))
2441 tmp.cbSize = sizeof(ICONMETRICSW);
2442 tmp.iHorzSpacing = lpimA->iHorzSpacing;
2443 tmp.iVertSpacing = lpimA->iVertSpacing;
2444 tmp.iTitleWrap = lpimA->iTitleWrap;
2445 SYSPARAMS_LogFont32ATo32W( &lpimA->lfFont, &tmp.lfFont);
2446 ret = SystemParametersInfoW( uiAction, uiParam, &tmp, fuWinIni );
2448 else
2449 ret = FALSE;
2450 break;
2453 case SPI_GETHIGHCONTRAST: /* 66 WINVER >= 0x400 */
2455 HIGHCONTRASTW tmp;
2456 LPHIGHCONTRASTA lphcA = pvParam;
2457 if (lphcA && lphcA->cbSize == sizeof(HIGHCONTRASTA))
2459 tmp.cbSize = sizeof(HIGHCONTRASTW);
2460 ret = SystemParametersInfoW( uiAction, uiParam, &tmp, fuWinIni );
2461 if (ret)
2463 lphcA->dwFlags = tmp.dwFlags;
2464 lphcA->lpszDefaultScheme = NULL; /* FIXME? */
2467 else
2468 ret = FALSE;
2469 break;
2472 case SPI_GETDESKWALLPAPER: /* 115 */
2474 WCHAR buffer[MAX_PATH];
2475 ret = (SystemParametersInfoW( SPI_GETDESKWALLPAPER, uiParam, buffer, fuWinIni ) &&
2476 WideCharToMultiByte(CP_ACP, 0, buffer, -1, pvParam, uiParam, NULL, NULL));
2477 break;
2480 default:
2481 ret = SystemParametersInfoW( uiAction, uiParam, pvParam, fuWinIni );
2482 break;
2484 return ret;
2488 /***********************************************************************
2489 * GetSystemMetrics (USER32.@)
2491 INT WINAPI GetSystemMetrics( INT index )
2493 struct monitor_info info;
2494 NONCLIENTMETRICSW ncm;
2495 MINIMIZEDMETRICS mm;
2496 ICONMETRICSW im;
2497 UINT ret;
2498 HDC hdc;
2500 /* some metrics are dynamic */
2501 switch (index)
2503 case SM_CXVSCROLL:
2504 case SM_CYHSCROLL:
2505 get_entry( &entry_SCROLLWIDTH, 0, &ret );
2506 return max( ret, 8 );
2507 case SM_CYCAPTION:
2508 ncm.cbSize = sizeof(ncm);
2509 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2510 return ncm.iCaptionHeight + 1;
2511 case SM_CXBORDER:
2512 case SM_CYBORDER:
2513 /* SM_C{X,Y}BORDER always returns 1 regardless of 'BorderWidth' value in registry */
2514 return 1;
2515 case SM_CXDLGFRAME:
2516 case SM_CYDLGFRAME:
2517 return 3;
2518 case SM_CYVTHUMB:
2519 case SM_CXHTHUMB:
2520 case SM_CYVSCROLL:
2521 case SM_CXHSCROLL:
2522 get_entry( &entry_SCROLLHEIGHT, 0, &ret );
2523 return max( ret, 8 );
2524 case SM_CXICON:
2525 case SM_CYICON:
2526 return map_to_dpi( 32, GetDpiForSystem() );
2527 case SM_CXCURSOR:
2528 case SM_CYCURSOR:
2529 ret = map_to_dpi( 32, GetDpiForSystem() );
2530 if (ret >= 64) return 64;
2531 if (ret >= 48) return 48;
2532 return 32;
2533 case SM_CYMENU:
2534 ncm.cbSize = sizeof(ncm);
2535 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2536 return ncm.iMenuHeight + 1;
2537 case SM_CXFULLSCREEN:
2538 /* see the remark for SM_CXMAXIMIZED, at least this formulation is
2539 * correct */
2540 return GetSystemMetrics( SM_CXMAXIMIZED) - 2 * GetSystemMetrics( SM_CXFRAME);
2541 case SM_CYFULLSCREEN:
2542 /* see the remark for SM_CYMAXIMIZED, at least this formulation is
2543 * correct */
2544 return GetSystemMetrics( SM_CYMAXIMIZED) - GetSystemMetrics( SM_CYMIN);
2545 case SM_CYKANJIWINDOW:
2546 return 0;
2547 case SM_MOUSEPRESENT:
2548 return 1;
2549 case SM_DEBUG:
2550 return 0;
2551 case SM_SWAPBUTTON:
2552 get_entry( &entry_MOUSEBUTTONSWAP, 0, &ret );
2553 return ret;
2554 case SM_RESERVED1:
2555 case SM_RESERVED2:
2556 case SM_RESERVED3:
2557 case SM_RESERVED4:
2558 return 0;
2559 case SM_CXMIN:
2560 ncm.cbSize = sizeof(ncm);
2561 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2562 hdc = get_display_dc();
2563 get_text_metr_size( hdc, &ncm.lfCaptionFont, NULL, &ret );
2564 release_display_dc( hdc );
2565 return 3 * ncm.iCaptionWidth + ncm.iCaptionHeight + 4 * ret + 2 * GetSystemMetrics(SM_CXFRAME) + 4;
2566 case SM_CYMIN:
2567 return GetSystemMetrics( SM_CYCAPTION) + 2 * GetSystemMetrics( SM_CYFRAME);
2568 case SM_CXSIZE:
2569 get_entry( &entry_CAPTIONWIDTH, 0, &ret );
2570 return max( ret, 8 );
2571 case SM_CYSIZE:
2572 ncm.cbSize = sizeof(ncm);
2573 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2574 return ncm.iCaptionHeight;
2575 case SM_CXFRAME:
2576 get_entry( &entry_BORDER, 0, &ret );
2577 ret = max( ret, 1 );
2578 return GetSystemMetrics(SM_CXDLGFRAME) + ret;
2579 case SM_CYFRAME:
2580 get_entry( &entry_BORDER, 0, &ret );
2581 ret = max( ret, 1 );
2582 return GetSystemMetrics(SM_CYDLGFRAME) + ret;
2583 case SM_CXMINTRACK:
2584 return GetSystemMetrics(SM_CXMIN);
2585 case SM_CYMINTRACK:
2586 return GetSystemMetrics(SM_CYMIN);
2587 case SM_CXDOUBLECLK:
2588 get_entry( &entry_DOUBLECLKWIDTH, 0, &ret );
2589 return ret;
2590 case SM_CYDOUBLECLK:
2591 get_entry( &entry_DOUBLECLKHEIGHT, 0, &ret );
2592 return ret;
2593 case SM_CXICONSPACING:
2594 im.cbSize = sizeof(im);
2595 SystemParametersInfoW( SPI_GETICONMETRICS, sizeof(im), &im, 0 );
2596 return im.iHorzSpacing;
2597 case SM_CYICONSPACING:
2598 im.cbSize = sizeof(im);
2599 SystemParametersInfoW( SPI_GETICONMETRICS, sizeof(im), &im, 0 );
2600 return im.iVertSpacing;
2601 case SM_MENUDROPALIGNMENT:
2602 SystemParametersInfoW( SPI_GETMENUDROPALIGNMENT, 0, &ret, 0 );
2603 return ret;
2604 case SM_PENWINDOWS:
2605 return 0;
2606 case SM_DBCSENABLED:
2608 CPINFO cpinfo;
2609 GetCPInfo( CP_ACP, &cpinfo );
2610 return (cpinfo.MaxCharSize > 1);
2612 case SM_CMOUSEBUTTONS:
2613 return 3;
2614 case SM_SECURE:
2615 return 0;
2616 case SM_CXEDGE:
2617 return GetSystemMetrics(SM_CXBORDER) + 1;
2618 case SM_CYEDGE:
2619 return GetSystemMetrics(SM_CYBORDER) + 1;
2620 case SM_CXMINSPACING:
2621 mm.cbSize = sizeof(mm);
2622 SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
2623 return GetSystemMetrics(SM_CXMINIMIZED) + mm.iHorzGap;
2624 case SM_CYMINSPACING:
2625 mm.cbSize = sizeof(mm);
2626 SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
2627 return GetSystemMetrics(SM_CYMINIMIZED) + mm.iVertGap;
2628 case SM_CXSMICON:
2629 case SM_CYSMICON:
2630 return map_to_dpi( 16, GetDpiForSystem() ) & ~1;
2631 case SM_CYSMCAPTION:
2632 ncm.cbSize = sizeof(ncm);
2633 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2634 return ncm.iSmCaptionHeight + 1;
2635 case SM_CXSMSIZE:
2636 get_entry( &entry_SMCAPTIONWIDTH, 0, &ret );
2637 return ret;
2638 case SM_CYSMSIZE:
2639 ncm.cbSize = sizeof(ncm);
2640 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2641 return ncm.iSmCaptionHeight;
2642 case SM_CXMENUSIZE:
2643 get_entry( &entry_MENUWIDTH, 0, &ret );
2644 return ret;
2645 case SM_CYMENUSIZE:
2646 ncm.cbSize = sizeof(ncm);
2647 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2648 return ncm.iMenuHeight;
2649 case SM_ARRANGE:
2650 mm.cbSize = sizeof(mm);
2651 SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
2652 return mm.iArrange;
2653 case SM_CXMINIMIZED:
2654 mm.cbSize = sizeof(mm);
2655 SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
2656 return mm.iWidth + 6;
2657 case SM_CYMINIMIZED:
2658 ncm.cbSize = sizeof(ncm);
2659 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2660 return ncm.iCaptionHeight + 6;
2661 case SM_CXMAXTRACK:
2662 return GetSystemMetrics(SM_CXVIRTUALSCREEN) + 4 + 2 * GetSystemMetrics(SM_CXFRAME);
2663 case SM_CYMAXTRACK:
2664 return GetSystemMetrics(SM_CYVIRTUALSCREEN) + 4 + 2 * GetSystemMetrics(SM_CYFRAME);
2665 case SM_CXMAXIMIZED:
2666 /* FIXME: subtract the width of any vertical application toolbars*/
2667 return GetSystemMetrics(SM_CXSCREEN) + 2 * GetSystemMetrics(SM_CXFRAME);
2668 case SM_CYMAXIMIZED:
2669 /* FIXME: subtract the width of any horizontal application toolbars*/
2670 return GetSystemMetrics(SM_CYSCREEN) + 2 * GetSystemMetrics(SM_CYCAPTION);
2671 case SM_NETWORK:
2672 return 3; /* FIXME */
2673 case SM_CLEANBOOT:
2674 return 0; /* 0 = ok, 1 = failsafe, 2 = failsafe + network */
2675 case SM_CXDRAG:
2676 get_entry( &entry_DRAGWIDTH, 0, &ret );
2677 return ret;
2678 case SM_CYDRAG:
2679 get_entry( &entry_DRAGHEIGHT, 0, &ret );
2680 return ret;
2681 case SM_SHOWSOUNDS:
2682 get_entry( &entry_SHOWSOUNDS, 0, &ret );
2683 return ret;
2684 case SM_CXMENUCHECK:
2685 case SM_CYMENUCHECK:
2687 TEXTMETRICW tm;
2688 ncm.cbSize = sizeof(ncm);
2689 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2690 hdc = get_display_dc();
2691 get_text_metr_size( hdc, &ncm.lfMenuFont, &tm, NULL);
2692 release_display_dc( hdc );
2693 return tm.tmHeight <= 0 ? 13 : ((tm.tmHeight + tm.tmExternalLeading + 1) / 2) * 2 - 1;
2695 case SM_SLOWMACHINE:
2696 return 0; /* Never true */
2697 case SM_MIDEASTENABLED:
2698 return 0; /* FIXME */
2699 case SM_MOUSEWHEELPRESENT:
2700 return 1;
2701 case SM_CXSCREEN:
2702 get_monitors_info( &info );
2703 return info.primary_rect.right - info.primary_rect.left;
2704 case SM_CYSCREEN:
2705 get_monitors_info( &info );
2706 return info.primary_rect.bottom - info.primary_rect.top;
2707 case SM_XVIRTUALSCREEN:
2708 get_monitors_info( &info );
2709 return info.virtual_rect.left;
2710 case SM_YVIRTUALSCREEN:
2711 get_monitors_info( &info );
2712 return info.virtual_rect.top;
2713 case SM_CXVIRTUALSCREEN:
2714 get_monitors_info( &info );
2715 return info.virtual_rect.right - info.virtual_rect.left;
2716 case SM_CYVIRTUALSCREEN:
2717 get_monitors_info( &info );
2718 return info.virtual_rect.bottom - info.virtual_rect.top;
2719 case SM_CMONITORS:
2720 get_monitors_info( &info );
2721 return info.count;
2722 case SM_SAMEDISPLAYFORMAT:
2723 return 1;
2724 case SM_IMMENABLED:
2725 return 0; /* FIXME */
2726 case SM_CXFOCUSBORDER:
2727 case SM_CYFOCUSBORDER:
2728 return 1;
2729 case SM_TABLETPC:
2730 case SM_MEDIACENTER:
2731 return 0;
2732 case SM_CMETRICS:
2733 return SM_CMETRICS;
2734 default:
2735 return 0;
2740 /***********************************************************************
2741 * GetSystemMetricsForDpi (USER32.@)
2743 INT WINAPI GetSystemMetricsForDpi( INT index, UINT dpi )
2745 NONCLIENTMETRICSW ncm;
2746 ICONMETRICSW im;
2747 UINT ret;
2748 HDC hdc;
2750 /* some metrics are dynamic */
2751 switch (index)
2753 case SM_CXVSCROLL:
2754 case SM_CYHSCROLL:
2755 get_entry_dpi( &entry_SCROLLWIDTH, 0, &ret, dpi );
2756 return max( ret, 8 );
2757 case SM_CYCAPTION:
2758 ncm.cbSize = sizeof(ncm);
2759 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2760 return ncm.iCaptionHeight + 1;
2761 case SM_CYVTHUMB:
2762 case SM_CXHTHUMB:
2763 case SM_CYVSCROLL:
2764 case SM_CXHSCROLL:
2765 get_entry_dpi( &entry_SCROLLHEIGHT, 0, &ret, dpi );
2766 return max( ret, 8 );
2767 case SM_CXICON:
2768 case SM_CYICON:
2769 return map_to_dpi( 32, dpi );
2770 case SM_CXCURSOR:
2771 case SM_CYCURSOR:
2772 ret = map_to_dpi( 32, dpi );
2773 if (ret >= 64) return 64;
2774 if (ret >= 48) return 48;
2775 return 32;
2776 case SM_CYMENU:
2777 ncm.cbSize = sizeof(ncm);
2778 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2779 return ncm.iMenuHeight + 1;
2780 case SM_CXSIZE:
2781 get_entry_dpi( &entry_CAPTIONWIDTH, 0, &ret, dpi );
2782 return max( ret, 8 );
2783 case SM_CYSIZE:
2784 ncm.cbSize = sizeof(ncm);
2785 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2786 return ncm.iCaptionHeight;
2787 case SM_CXFRAME:
2788 get_entry_dpi( &entry_BORDER, 0, &ret, dpi );
2789 ret = max( ret, 1 );
2790 return GetSystemMetricsForDpi( SM_CXDLGFRAME, dpi ) + ret;
2791 case SM_CYFRAME:
2792 get_entry_dpi( &entry_BORDER, 0, &ret, dpi );
2793 ret = max( ret, 1 );
2794 return GetSystemMetricsForDpi( SM_CYDLGFRAME, dpi ) + ret;
2795 case SM_CXICONSPACING:
2796 im.cbSize = sizeof(im);
2797 SystemParametersInfoForDpi( SPI_GETICONMETRICS, sizeof(im), &im, 0, dpi );
2798 return im.iHorzSpacing;
2799 case SM_CYICONSPACING:
2800 im.cbSize = sizeof(im);
2801 SystemParametersInfoForDpi( SPI_GETICONMETRICS, sizeof(im), &im, 0, dpi );
2802 return im.iVertSpacing;
2803 case SM_CXSMICON:
2804 case SM_CYSMICON:
2805 return map_to_dpi( 16, dpi ) & ~1;
2806 case SM_CYSMCAPTION:
2807 ncm.cbSize = sizeof(ncm);
2808 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2809 return ncm.iSmCaptionHeight + 1;
2810 case SM_CXSMSIZE:
2811 get_entry_dpi( &entry_SMCAPTIONWIDTH, 0, &ret, dpi );
2812 return ret;
2813 case SM_CYSMSIZE:
2814 ncm.cbSize = sizeof(ncm);
2815 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2816 return ncm.iSmCaptionHeight;
2817 case SM_CXMENUSIZE:
2818 get_entry_dpi( &entry_MENUWIDTH, 0, &ret, dpi );
2819 return ret;
2820 case SM_CYMENUSIZE:
2821 ncm.cbSize = sizeof(ncm);
2822 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2823 return ncm.iMenuHeight;
2824 case SM_CXMENUCHECK:
2825 case SM_CYMENUCHECK:
2827 TEXTMETRICW tm;
2828 ncm.cbSize = sizeof(ncm);
2829 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2830 hdc = get_display_dc();
2831 get_text_metr_size( hdc, &ncm.lfMenuFont, &tm, NULL);
2832 release_display_dc( hdc );
2833 return tm.tmHeight <= 0 ? 13 : ((tm.tmHeight + tm.tmExternalLeading - 1) | 1);
2835 default:
2836 return GetSystemMetrics( index );
2841 /***********************************************************************
2842 * SwapMouseButton (USER32.@)
2843 * Reverse or restore the meaning of the left and right mouse buttons
2844 * fSwap [I ] TRUE - reverse, FALSE - original
2845 * RETURN
2846 * previous state
2848 BOOL WINAPI SwapMouseButton( BOOL fSwap )
2850 BOOL prev = GetSystemMetrics(SM_SWAPBUTTON);
2851 SystemParametersInfoW(SPI_SETMOUSEBUTTONSWAP, fSwap, 0, 0);
2852 return prev;
2856 /**********************************************************************
2857 * SetDoubleClickTime (USER32.@)
2859 BOOL WINAPI SetDoubleClickTime( UINT interval )
2861 return SystemParametersInfoW(SPI_SETDOUBLECLICKTIME, interval, 0, 0);
2865 /**********************************************************************
2866 * GetDoubleClickTime (USER32.@)
2868 UINT WINAPI GetDoubleClickTime(void)
2870 UINT time = 0;
2872 get_entry( &entry_DOUBLECLICKTIME, 0, &time );
2873 if (!time) time = 500;
2874 return time;
2878 /*************************************************************************
2879 * GetSysColor (USER32.@)
2881 COLORREF WINAPI DECLSPEC_HOTPATCH GetSysColor( INT nIndex )
2883 COLORREF ret = 0;
2885 if (nIndex >= 0 && nIndex < ARRAY_SIZE( system_colors ))
2886 get_entry( &system_colors[nIndex], 0, &ret );
2887 return ret;
2891 /*************************************************************************
2892 * SetSysColors (USER32.@)
2894 BOOL WINAPI SetSysColors( INT count, const INT *colors, const COLORREF *values )
2896 int i;
2898 if (IS_INTRESOURCE(colors)) return FALSE; /* stupid app passes a color instead of an array */
2900 for (i = 0; i < count; i++)
2901 if (colors[i] >= 0 && colors[i] <= ARRAY_SIZE( system_colors ))
2902 set_entry( &system_colors[colors[i]], values[i], 0, 0 );
2904 /* Send WM_SYSCOLORCHANGE message to all windows */
2906 SendMessageTimeoutW( HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0, SMTO_ABORTIFHUNG, 2000, NULL );
2908 /* Repaint affected portions of all visible windows */
2910 RedrawWindow( 0, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN );
2911 return TRUE;
2915 /*************************************************************************
2916 * SetSysColorsTemp (USER32.@)
2918 DWORD_PTR WINAPI SetSysColorsTemp( const COLORREF *pPens, const HBRUSH *pBrushes, DWORD_PTR n)
2920 FIXME( "no longer supported\n" );
2921 return FALSE;
2925 /***********************************************************************
2926 * GetSysColorBrush (USER32.@)
2928 HBRUSH WINAPI DECLSPEC_HOTPATCH GetSysColorBrush( INT index )
2930 if (index < 0 || index >= ARRAY_SIZE( system_colors )) return 0;
2932 if (!system_colors[index].brush)
2934 HBRUSH brush = CreateSolidBrush( GetSysColor( index ));
2935 __wine_make_gdi_object_system( brush, TRUE );
2936 if (InterlockedCompareExchangePointer( (void **)&system_colors[index].brush, brush, 0 ))
2938 __wine_make_gdi_object_system( brush, FALSE );
2939 DeleteObject( brush );
2942 return system_colors[index].brush;
2946 /***********************************************************************
2947 * SYSCOLOR_GetPen
2949 HPEN SYSCOLOR_GetPen( INT index )
2951 /* We can assert here, because this function is internal to Wine */
2952 assert (0 <= index && index < ARRAY_SIZE( system_colors ));
2954 if (!system_colors[index].pen)
2956 HPEN pen = CreatePen( PS_SOLID, 1, GetSysColor( index ));
2957 __wine_make_gdi_object_system( pen, TRUE );
2958 if (InterlockedCompareExchangePointer( (void **)&system_colors[index].pen, pen, 0 ))
2960 __wine_make_gdi_object_system( pen, FALSE );
2961 DeleteObject( pen );
2964 return system_colors[index].pen;
2968 /***********************************************************************
2969 * SYSCOLOR_Get55AABrush
2971 HBRUSH SYSCOLOR_Get55AABrush(void)
2973 static const WORD pattern[] = { 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa };
2974 static HBRUSH brush_55aa;
2976 if (!brush_55aa)
2978 HBITMAP bitmap = CreateBitmap( 8, 8, 1, 1, pattern );
2979 HBRUSH brush = CreatePatternBrush( bitmap );
2980 DeleteObject( bitmap );
2981 __wine_make_gdi_object_system( brush, TRUE );
2982 if (InterlockedCompareExchangePointer( (void **)&brush_55aa, brush, 0 ))
2984 __wine_make_gdi_object_system( brush, FALSE );
2985 DeleteObject( brush );
2988 return brush_55aa;
2991 /***********************************************************************
2992 * ChangeDisplaySettingsA (USER32.@)
2994 LONG WINAPI ChangeDisplaySettingsA( LPDEVMODEA devmode, DWORD flags )
2996 if (devmode) devmode->dmDriverExtra = 0;
2998 return ChangeDisplaySettingsExA(NULL,devmode,NULL,flags,NULL);
3002 /***********************************************************************
3003 * ChangeDisplaySettingsW (USER32.@)
3005 LONG WINAPI ChangeDisplaySettingsW( LPDEVMODEW devmode, DWORD flags )
3007 if (devmode) devmode->dmDriverExtra = 0;
3009 return ChangeDisplaySettingsExW(NULL,devmode,NULL,flags,NULL);
3013 /***********************************************************************
3014 * ChangeDisplaySettingsExA (USER32.@)
3016 LONG WINAPI ChangeDisplaySettingsExA( LPCSTR devname, LPDEVMODEA devmode, HWND hwnd,
3017 DWORD flags, LPVOID lparam )
3019 LONG ret;
3020 UNICODE_STRING nameW;
3022 if (devname) RtlCreateUnicodeStringFromAsciiz(&nameW, devname);
3023 else nameW.Buffer = NULL;
3025 if (devmode)
3027 DEVMODEW *devmodeW;
3029 devmodeW = GdiConvertToDevmodeW(devmode);
3030 if (devmodeW)
3032 ret = ChangeDisplaySettingsExW(nameW.Buffer, devmodeW, hwnd, flags, lparam);
3033 HeapFree(GetProcessHeap(), 0, devmodeW);
3035 else
3036 ret = DISP_CHANGE_SUCCESSFUL;
3038 else
3040 ret = ChangeDisplaySettingsExW(nameW.Buffer, NULL, hwnd, flags, lparam);
3043 if (devname) RtlFreeUnicodeString(&nameW);
3044 return ret;
3047 #define _X_FIELD(prefix, bits) \
3048 if ((fields) & prefix##_##bits) \
3050 p += sprintf(p, "%s%s", first ? "" : ",", #bits); \
3051 first = FALSE; \
3054 static const CHAR *_CDS_flags(DWORD fields)
3056 BOOL first = TRUE;
3057 CHAR buf[128];
3058 CHAR *p = buf;
3060 _X_FIELD(CDS, UPDATEREGISTRY)
3061 _X_FIELD(CDS, TEST)
3062 _X_FIELD(CDS, FULLSCREEN)
3063 _X_FIELD(CDS, GLOBAL)
3064 _X_FIELD(CDS, SET_PRIMARY)
3065 _X_FIELD(CDS, VIDEOPARAMETERS)
3066 _X_FIELD(CDS, ENABLE_UNSAFE_MODES)
3067 _X_FIELD(CDS, DISABLE_UNSAFE_MODES)
3068 _X_FIELD(CDS, RESET)
3069 _X_FIELD(CDS, RESET_EX)
3070 _X_FIELD(CDS, NORESET)
3072 *p = 0;
3073 return wine_dbg_sprintf("%s", buf);
3076 static const CHAR *_DM_fields(DWORD fields)
3078 BOOL first = TRUE;
3079 CHAR buf[128];
3080 CHAR *p = buf;
3082 _X_FIELD(DM, BITSPERPEL)
3083 _X_FIELD(DM, PELSWIDTH)
3084 _X_FIELD(DM, PELSHEIGHT)
3085 _X_FIELD(DM, DISPLAYFLAGS)
3086 _X_FIELD(DM, DISPLAYFREQUENCY)
3087 _X_FIELD(DM, POSITION)
3088 _X_FIELD(DM, DISPLAYORIENTATION)
3090 *p = 0;
3091 return wine_dbg_sprintf("%s", buf);
3094 #undef _X_FIELD
3096 static void trace_devmode(const DEVMODEW *devmode)
3098 TRACE("dmFields=%s ", _DM_fields(devmode->dmFields));
3099 if (devmode->dmFields & DM_BITSPERPEL)
3100 TRACE("dmBitsPerPel=%u ", devmode->dmBitsPerPel);
3101 if (devmode->dmFields & DM_PELSWIDTH)
3102 TRACE("dmPelsWidth=%u ", devmode->dmPelsWidth);
3103 if (devmode->dmFields & DM_PELSHEIGHT)
3104 TRACE("dmPelsHeight=%u ", devmode->dmPelsHeight);
3105 if (devmode->dmFields & DM_DISPLAYFREQUENCY)
3106 TRACE("dmDisplayFrequency=%u ", devmode->dmDisplayFrequency);
3107 if (devmode->dmFields & DM_POSITION)
3108 TRACE("dmPosition=(%d,%d) ", devmode->u1.s2.dmPosition.x, devmode->u1.s2.dmPosition.y);
3109 if (devmode->dmFields & DM_DISPLAYFLAGS)
3110 TRACE("dmDisplayFlags=%#x ", devmode->u2.dmDisplayFlags);
3111 if (devmode->dmFields & DM_DISPLAYORIENTATION)
3112 TRACE("dmDisplayOrientation=%u ", devmode->u1.s2.dmDisplayOrientation);
3113 TRACE("\n");
3116 static BOOL is_detached_mode(const DEVMODEW *mode)
3118 return mode->dmFields & DM_POSITION &&
3119 mode->dmFields & DM_PELSWIDTH &&
3120 mode->dmFields & DM_PELSHEIGHT &&
3121 mode->dmPelsWidth == 0 &&
3122 mode->dmPelsHeight == 0;
3125 /***********************************************************************
3126 * ChangeDisplaySettingsExW (USER32.@)
3128 LONG WINAPI ChangeDisplaySettingsExW( LPCWSTR devname, LPDEVMODEW devmode, HWND hwnd,
3129 DWORD flags, LPVOID lparam )
3131 WCHAR primary_adapter[CCHDEVICENAME];
3132 BOOL def_mode = TRUE;
3133 DEVMODEW dm;
3134 LONG ret;
3136 TRACE("%s %p %p %#x %p\n", debugstr_w(devname), devmode, hwnd, flags, lparam);
3137 TRACE("flags=%s\n", _CDS_flags(flags));
3139 if (!devname && !devmode)
3141 ret = USER_Driver->pChangeDisplaySettingsEx(NULL, NULL, hwnd, flags, lparam);
3142 if (ret != DISP_CHANGE_SUCCESSFUL)
3143 ERR("Restoring all displays to their registry settings returned %d.\n", ret);
3144 return ret;
3147 if (!devname && devmode)
3149 if (!get_primary_adapter(primary_adapter))
3150 return DISP_CHANGE_FAILED;
3152 devname = primary_adapter;
3155 if (!is_valid_adapter_name(devname))
3157 ERR("Invalid device name %s.\n", wine_dbgstr_w(devname));
3158 return DISP_CHANGE_BADPARAM;
3161 if (devmode)
3163 trace_devmode(devmode);
3165 if (devmode->dmSize < FIELD_OFFSET(DEVMODEW, dmICMMethod))
3166 return DISP_CHANGE_BADMODE;
3168 if (is_detached_mode(devmode) ||
3169 ((devmode->dmFields & DM_BITSPERPEL) && devmode->dmBitsPerPel) ||
3170 ((devmode->dmFields & DM_PELSWIDTH) && devmode->dmPelsWidth) ||
3171 ((devmode->dmFields & DM_PELSHEIGHT) && devmode->dmPelsHeight) ||
3172 ((devmode->dmFields & DM_DISPLAYFREQUENCY) && devmode->dmDisplayFrequency))
3173 def_mode = FALSE;
3176 if (def_mode)
3178 memset(&dm, 0, sizeof(dm));
3179 dm.dmSize = sizeof(dm);
3180 if (!EnumDisplaySettingsExW(devname, ENUM_REGISTRY_SETTINGS, &dm, 0))
3182 ERR("Default mode not found!\n");
3183 return DISP_CHANGE_BADMODE;
3186 TRACE("Return to original display mode\n");
3187 devmode = &dm;
3190 if ((devmode->dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != (DM_PELSWIDTH | DM_PELSHEIGHT))
3192 WARN("devmode doesn't specify the resolution: %#x\n", devmode->dmFields);
3193 return DISP_CHANGE_BADMODE;
3196 if (!is_detached_mode(devmode) && (!devmode->dmPelsWidth || !devmode->dmPelsHeight))
3198 memset(&dm, 0, sizeof(dm));
3199 dm.dmSize = sizeof(dm);
3200 if (!EnumDisplaySettingsExW(devname, ENUM_CURRENT_SETTINGS, &dm, 0))
3202 ERR("Current mode not found!\n");
3203 return DISP_CHANGE_BADMODE;
3206 if (!devmode->dmPelsWidth)
3207 devmode->dmPelsWidth = dm.dmPelsWidth;
3208 if (!devmode->dmPelsHeight)
3209 devmode->dmPelsHeight = dm.dmPelsHeight;
3212 ret = USER_Driver->pChangeDisplaySettingsEx(devname, devmode, hwnd, flags, lparam);
3213 if (ret != DISP_CHANGE_SUCCESSFUL)
3214 ERR("Changing %s display settings returned %d.\n", wine_dbgstr_w(devname), ret);
3215 return ret;
3219 /***********************************************************************
3220 * EnumDisplaySettingsW (USER32.@)
3222 * RETURNS
3223 * TRUE if nth setting exists found (described in the LPDEVMODEW struct)
3224 * FALSE if we do not have the nth setting
3226 BOOL WINAPI EnumDisplaySettingsW( LPCWSTR name, DWORD n, LPDEVMODEW devmode )
3228 return EnumDisplaySettingsExW(name, n, devmode, 0);
3232 /***********************************************************************
3233 * EnumDisplaySettingsA (USER32.@)
3235 BOOL WINAPI EnumDisplaySettingsA(LPCSTR name,DWORD n,LPDEVMODEA devmode)
3237 return EnumDisplaySettingsExA(name, n, devmode, 0);
3241 /***********************************************************************
3242 * EnumDisplaySettingsExA (USER32.@)
3244 BOOL WINAPI EnumDisplaySettingsExA(LPCSTR lpszDeviceName, DWORD iModeNum,
3245 LPDEVMODEA lpDevMode, DWORD dwFlags)
3247 DEVMODEW devmodeW;
3248 BOOL ret;
3249 UNICODE_STRING nameW;
3251 if (lpszDeviceName) RtlCreateUnicodeStringFromAsciiz(&nameW, lpszDeviceName);
3252 else nameW.Buffer = NULL;
3254 memset(&devmodeW, 0, sizeof(devmodeW));
3255 devmodeW.dmSize = sizeof(devmodeW);
3256 ret = EnumDisplaySettingsExW(nameW.Buffer,iModeNum,&devmodeW,dwFlags);
3257 if (ret)
3259 lpDevMode->dmSize = FIELD_OFFSET(DEVMODEA, dmICMMethod);
3260 lpDevMode->dmSpecVersion = devmodeW.dmSpecVersion;
3261 lpDevMode->dmDriverVersion = devmodeW.dmDriverVersion;
3262 WideCharToMultiByte(CP_ACP, 0, devmodeW.dmDeviceName, -1,
3263 (LPSTR)lpDevMode->dmDeviceName, CCHDEVICENAME, NULL, NULL);
3264 lpDevMode->dmDriverExtra = 0; /* FIXME */
3265 lpDevMode->dmBitsPerPel = devmodeW.dmBitsPerPel;
3266 lpDevMode->dmPelsHeight = devmodeW.dmPelsHeight;
3267 lpDevMode->dmPelsWidth = devmodeW.dmPelsWidth;
3268 lpDevMode->u2.dmDisplayFlags = devmodeW.u2.dmDisplayFlags;
3269 lpDevMode->dmDisplayFrequency = devmodeW.dmDisplayFrequency;
3270 lpDevMode->dmFields = devmodeW.dmFields;
3272 lpDevMode->u1.s2.dmPosition.x = devmodeW.u1.s2.dmPosition.x;
3273 lpDevMode->u1.s2.dmPosition.y = devmodeW.u1.s2.dmPosition.y;
3274 lpDevMode->u1.s2.dmDisplayOrientation = devmodeW.u1.s2.dmDisplayOrientation;
3275 lpDevMode->u1.s2.dmDisplayFixedOutput = devmodeW.u1.s2.dmDisplayFixedOutput;
3277 if (lpszDeviceName) RtlFreeUnicodeString(&nameW);
3278 return ret;
3282 /***********************************************************************
3283 * EnumDisplaySettingsExW (USER32.@)
3285 BOOL WINAPI EnumDisplaySettingsExW(LPCWSTR lpszDeviceName, DWORD iModeNum,
3286 LPDEVMODEW lpDevMode, DWORD dwFlags)
3288 WCHAR primary_adapter[CCHDEVICENAME];
3289 BOOL ret;
3291 TRACE("%s %#x %p %#x\n", wine_dbgstr_w(lpszDeviceName), iModeNum, lpDevMode, dwFlags);
3293 if (!lpszDeviceName)
3295 if (!get_primary_adapter(primary_adapter))
3296 return FALSE;
3298 lpszDeviceName = primary_adapter;
3301 if (!is_valid_adapter_name(lpszDeviceName))
3303 ERR("Invalid device name %s.\n", wine_dbgstr_w(lpszDeviceName));
3304 return FALSE;
3307 ret = USER_Driver->pEnumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, dwFlags);
3308 if (ret)
3309 TRACE("device:%s mode index:%#x position:(%d,%d) resolution:%ux%u frequency:%uHz "
3310 "depth:%ubits orientation:%#x.\n", wine_dbgstr_w(lpszDeviceName), iModeNum,
3311 lpDevMode->u1.s2.dmPosition.x, lpDevMode->u1.s2.dmPosition.y, lpDevMode->dmPelsWidth,
3312 lpDevMode->dmPelsHeight, lpDevMode->dmDisplayFrequency, lpDevMode->dmBitsPerPel,
3313 lpDevMode->u1.s2.dmDisplayOrientation);
3314 else
3315 WARN("Failed to query %s display settings.\n", wine_dbgstr_w(lpszDeviceName));
3316 return ret;
3320 /**********************************************************************
3321 * get_monitor_dpi
3323 UINT get_monitor_dpi( HMONITOR monitor )
3325 /* FIXME: use the monitor DPI instead */
3326 return system_dpi;
3329 /**********************************************************************
3330 * get_win_monitor_dpi
3332 UINT get_win_monitor_dpi( HWND hwnd )
3334 /* FIXME: use the monitor DPI instead */
3335 return system_dpi;
3338 /**********************************************************************
3339 * get_thread_dpi
3341 UINT get_thread_dpi(void)
3343 switch (GetAwarenessFromDpiAwarenessContext( GetThreadDpiAwarenessContext() ))
3345 case DPI_AWARENESS_UNAWARE: return USER_DEFAULT_SCREEN_DPI;
3346 case DPI_AWARENESS_SYSTEM_AWARE: return system_dpi;
3347 default: return 0; /* no scaling */
3351 /**********************************************************************
3352 * map_dpi_point
3354 POINT map_dpi_point( POINT pt, UINT dpi_from, UINT dpi_to )
3356 if (dpi_from && dpi_to && dpi_from != dpi_to)
3358 pt.x = MulDiv( pt.x, dpi_to, dpi_from );
3359 pt.y = MulDiv( pt.y, dpi_to, dpi_from );
3361 return pt;
3364 /**********************************************************************
3365 * point_win_to_phys_dpi
3367 POINT point_win_to_phys_dpi( HWND hwnd, POINT pt )
3369 return map_dpi_point( pt, GetDpiForWindow( hwnd ), get_win_monitor_dpi( hwnd ) );
3372 /**********************************************************************
3373 * point_phys_to_win_dpi
3375 POINT point_phys_to_win_dpi( HWND hwnd, POINT pt )
3377 return map_dpi_point( pt, get_win_monitor_dpi( hwnd ), GetDpiForWindow( hwnd ));
3380 /**********************************************************************
3381 * point_win_to_thread_dpi
3383 POINT point_win_to_thread_dpi( HWND hwnd, POINT pt )
3385 UINT dpi = get_thread_dpi();
3386 if (!dpi) dpi = get_win_monitor_dpi( hwnd );
3387 return map_dpi_point( pt, GetDpiForWindow( hwnd ), dpi );
3390 /**********************************************************************
3391 * point_thread_to_win_dpi
3393 POINT point_thread_to_win_dpi( HWND hwnd, POINT pt )
3395 UINT dpi = get_thread_dpi();
3396 if (!dpi) dpi = get_win_monitor_dpi( hwnd );
3397 return map_dpi_point( pt, dpi, GetDpiForWindow( hwnd ));
3400 /**********************************************************************
3401 * map_dpi_rect
3403 RECT map_dpi_rect( RECT rect, UINT dpi_from, UINT dpi_to )
3405 if (dpi_from && dpi_to && dpi_from != dpi_to)
3407 rect.left = MulDiv( rect.left, dpi_to, dpi_from );
3408 rect.top = MulDiv( rect.top, dpi_to, dpi_from );
3409 rect.right = MulDiv( rect.right, dpi_to, dpi_from );
3410 rect.bottom = MulDiv( rect.bottom, dpi_to, dpi_from );
3412 return rect;
3415 /**********************************************************************
3416 * rect_win_to_thread_dpi
3418 RECT rect_win_to_thread_dpi( HWND hwnd, RECT rect )
3420 UINT dpi = get_thread_dpi();
3421 if (!dpi) dpi = get_win_monitor_dpi( hwnd );
3422 return map_dpi_rect( rect, GetDpiForWindow( hwnd ), dpi );
3425 /**********************************************************************
3426 * rect_thread_to_win_dpi
3428 RECT rect_thread_to_win_dpi( HWND hwnd, RECT rect )
3430 UINT dpi = get_thread_dpi();
3431 if (!dpi) dpi = get_win_monitor_dpi( hwnd );
3432 return map_dpi_rect( rect, dpi, GetDpiForWindow( hwnd ) );
3435 /**********************************************************************
3436 * SetProcessDpiAwarenessContext (USER32.@)
3438 BOOL WINAPI SetProcessDpiAwarenessContext( DPI_AWARENESS_CONTEXT context )
3440 DPI_AWARENESS val = GetAwarenessFromDpiAwarenessContext( context );
3442 if (val == DPI_AWARENESS_INVALID)
3444 SetLastError( ERROR_INVALID_PARAMETER );
3445 return FALSE;
3447 val |= 0x10; /* avoid 0 value */
3448 if (InterlockedCompareExchange( &dpi_awareness, val, 0 ))
3450 SetLastError( ERROR_ACCESS_DENIED );
3451 return FALSE;
3453 TRACE( "set to %p\n", context );
3454 return TRUE;
3457 /**********************************************************************
3458 * GetProcessDpiAwarenessInternal (USER32.@)
3460 BOOL WINAPI GetProcessDpiAwarenessInternal( HANDLE process, DPI_AWARENESS *awareness )
3462 if (process && process != GetCurrentProcess())
3464 WARN( "not supported on other process %p\n", process );
3465 *awareness = DPI_AWARENESS_UNAWARE;
3467 else *awareness = dpi_awareness & 3;
3468 return TRUE;
3471 /**********************************************************************
3472 * SetProcessDpiAwarenessInternal (USER32.@)
3474 BOOL WINAPI SetProcessDpiAwarenessInternal( DPI_AWARENESS awareness )
3476 static const DPI_AWARENESS_CONTEXT contexts[3] = { DPI_AWARENESS_CONTEXT_UNAWARE,
3477 DPI_AWARENESS_CONTEXT_SYSTEM_AWARE,
3478 DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE };
3480 if (awareness < DPI_AWARENESS_UNAWARE || awareness > DPI_AWARENESS_PER_MONITOR_AWARE)
3482 SetLastError( ERROR_INVALID_PARAMETER );
3483 return FALSE;
3485 return SetProcessDpiAwarenessContext( contexts[awareness] );
3488 /***********************************************************************
3489 * AreDpiAwarenessContextsEqual (USER32.@)
3491 BOOL WINAPI AreDpiAwarenessContextsEqual( DPI_AWARENESS_CONTEXT ctx1, DPI_AWARENESS_CONTEXT ctx2 )
3493 DPI_AWARENESS aware1 = GetAwarenessFromDpiAwarenessContext( ctx1 );
3494 DPI_AWARENESS aware2 = GetAwarenessFromDpiAwarenessContext( ctx2 );
3495 return aware1 != DPI_AWARENESS_INVALID && aware1 == aware2;
3498 /***********************************************************************
3499 * GetAwarenessFromDpiAwarenessContext (USER32.@)
3501 DPI_AWARENESS WINAPI GetAwarenessFromDpiAwarenessContext( DPI_AWARENESS_CONTEXT context )
3503 switch ((ULONG_PTR)context)
3505 case 0x10:
3506 case 0x11:
3507 case 0x12:
3508 case 0x80000010:
3509 case 0x80000011:
3510 case 0x80000012:
3511 return (ULONG_PTR)context & 3;
3512 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE:
3513 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE:
3514 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE:
3515 return ~(ULONG_PTR)context;
3516 default:
3517 return DPI_AWARENESS_INVALID;
3521 /***********************************************************************
3522 * IsValidDpiAwarenessContext (USER32.@)
3524 BOOL WINAPI IsValidDpiAwarenessContext( DPI_AWARENESS_CONTEXT context )
3526 return GetAwarenessFromDpiAwarenessContext( context ) != DPI_AWARENESS_INVALID;
3529 /***********************************************************************
3530 * SetProcessDPIAware (USER32.@)
3532 BOOL WINAPI SetProcessDPIAware(void)
3534 TRACE("\n");
3535 InterlockedCompareExchange( &dpi_awareness, 0x11, 0 );
3536 return TRUE;
3539 /***********************************************************************
3540 * IsProcessDPIAware (USER32.@)
3542 BOOL WINAPI IsProcessDPIAware(void)
3544 return GetAwarenessFromDpiAwarenessContext( GetThreadDpiAwarenessContext() ) != DPI_AWARENESS_UNAWARE;
3547 /**********************************************************************
3548 * EnableNonClientDpiScaling (USER32.@)
3550 BOOL WINAPI EnableNonClientDpiScaling( HWND hwnd )
3552 FIXME("(%p): stub\n", hwnd);
3553 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
3554 return FALSE;
3557 /***********************************************************************
3558 * GetDpiForSystem (USER32.@)
3560 UINT WINAPI GetDpiForSystem(void)
3562 if (!IsProcessDPIAware()) return USER_DEFAULT_SCREEN_DPI;
3563 return system_dpi;
3566 /***********************************************************************
3567 * GetDpiForMonitorInternal (USER32.@)
3569 BOOL WINAPI GetDpiForMonitorInternal( HMONITOR monitor, UINT type, UINT *x, UINT *y )
3571 if (type > 2)
3573 SetLastError( ERROR_BAD_ARGUMENTS );
3574 return FALSE;
3576 if (!x || !y)
3578 SetLastError( ERROR_INVALID_ADDRESS );
3579 return FALSE;
3581 switch (GetAwarenessFromDpiAwarenessContext( GetThreadDpiAwarenessContext() ))
3583 case DPI_AWARENESS_UNAWARE: *x = *y = USER_DEFAULT_SCREEN_DPI; break;
3584 case DPI_AWARENESS_SYSTEM_AWARE: *x = *y = system_dpi; break;
3585 default: *x = *y = get_monitor_dpi( monitor ); break;
3587 return TRUE;
3590 /**********************************************************************
3591 * GetThreadDpiAwarenessContext (USER32.@)
3593 DPI_AWARENESS_CONTEXT WINAPI GetThreadDpiAwarenessContext(void)
3595 struct user_thread_info *info = get_user_thread_info();
3597 if (info->dpi_awareness) return ULongToHandle( info->dpi_awareness );
3598 if (dpi_awareness) return ULongToHandle( dpi_awareness );
3599 return ULongToHandle( 0x10 | default_awareness );
3602 /**********************************************************************
3603 * SetThreadDpiAwarenessContext (USER32.@)
3605 DPI_AWARENESS_CONTEXT WINAPI SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT context )
3607 struct user_thread_info *info = get_user_thread_info();
3608 DPI_AWARENESS prev, val = GetAwarenessFromDpiAwarenessContext( context );
3610 if (val == DPI_AWARENESS_INVALID)
3612 SetLastError( ERROR_INVALID_PARAMETER );
3613 return 0;
3615 if (!(prev = info->dpi_awareness))
3617 prev = dpi_awareness;
3618 if (!prev) prev = 0x10 | DPI_AWARENESS_UNAWARE;
3619 prev |= 0x80000000; /* restore to process default */
3621 if (((ULONG_PTR)context & ~(ULONG_PTR)0x13) == 0x80000000) info->dpi_awareness = 0;
3622 else info->dpi_awareness = val | 0x10;
3623 return ULongToHandle( prev );
3626 /**********************************************************************
3627 * LogicalToPhysicalPointForPerMonitorDPI (USER32.@)
3629 BOOL WINAPI LogicalToPhysicalPointForPerMonitorDPI( HWND hwnd, POINT *pt )
3631 RECT rect;
3633 if (!GetWindowRect( hwnd, &rect )) return FALSE;
3634 if (pt->x < rect.left || pt->y < rect.top || pt->x > rect.right || pt->y > rect.bottom) return FALSE;
3635 *pt = point_win_to_phys_dpi( hwnd, *pt );
3636 return TRUE;
3639 /**********************************************************************
3640 * PhysicalToLogicalPointForPerMonitorDPI (USER32.@)
3642 BOOL WINAPI PhysicalToLogicalPointForPerMonitorDPI( HWND hwnd, POINT *pt )
3644 DPI_AWARENESS_CONTEXT context;
3645 RECT rect;
3646 BOOL ret = FALSE;
3648 context = SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
3649 if (GetWindowRect( hwnd, &rect ) &&
3650 pt->x >= rect.left && pt->y >= rect.top && pt->x <= rect.right && pt->y <= rect.bottom)
3652 *pt = point_phys_to_win_dpi( hwnd, *pt );
3653 ret = TRUE;
3655 SetThreadDpiAwarenessContext( context );
3656 return ret;
3659 struct monitor_enum_info
3661 RECT rect;
3662 UINT max_area;
3663 UINT min_distance;
3664 HMONITOR primary;
3665 HMONITOR nearest;
3666 HMONITOR ret;
3669 /* helper callback for MonitorFromRect */
3670 static BOOL CALLBACK monitor_enum( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
3672 struct monitor_enum_info *info = (struct monitor_enum_info *)lp;
3673 RECT intersect;
3675 if (IntersectRect( &intersect, rect, &info->rect ))
3677 /* check for larger intersecting area */
3678 UINT area = (intersect.right - intersect.left) * (intersect.bottom - intersect.top);
3679 if (area > info->max_area)
3681 info->max_area = area;
3682 info->ret = monitor;
3685 else if (!info->max_area) /* if not intersecting, check for min distance */
3687 UINT distance;
3688 UINT x, y;
3690 if (info->rect.right <= rect->left) x = rect->left - info->rect.right;
3691 else if (rect->right <= info->rect.left) x = info->rect.left - rect->right;
3692 else x = 0;
3693 if (info->rect.bottom <= rect->top) y = rect->top - info->rect.bottom;
3694 else if (rect->bottom <= info->rect.top) y = info->rect.top - rect->bottom;
3695 else y = 0;
3696 distance = x * x + y * y;
3697 if (distance < info->min_distance)
3699 info->min_distance = distance;
3700 info->nearest = monitor;
3703 if (!info->primary)
3705 MONITORINFO mon_info;
3706 mon_info.cbSize = sizeof(mon_info);
3707 GetMonitorInfoW( monitor, &mon_info );
3708 if (mon_info.dwFlags & MONITORINFOF_PRIMARY) info->primary = monitor;
3710 return TRUE;
3713 /***********************************************************************
3714 * MonitorFromRect (USER32.@)
3716 HMONITOR WINAPI MonitorFromRect( const RECT *rect, DWORD flags )
3718 struct monitor_enum_info info;
3720 info.rect = *rect;
3721 info.max_area = 0;
3722 info.min_distance = ~0u;
3723 info.primary = 0;
3724 info.nearest = 0;
3725 info.ret = 0;
3727 if (IsRectEmpty(&info.rect))
3729 info.rect.right = info.rect.left + 1;
3730 info.rect.bottom = info.rect.top + 1;
3733 if (!EnumDisplayMonitors( 0, NULL, monitor_enum, (LPARAM)&info )) return 0;
3734 if (!info.ret)
3736 if (flags & MONITOR_DEFAULTTOPRIMARY) info.ret = info.primary;
3737 else if (flags & MONITOR_DEFAULTTONEAREST) info.ret = info.nearest;
3740 TRACE( "%s flags %x returning %p\n", wine_dbgstr_rect(rect), flags, info.ret );
3741 return info.ret;
3744 /***********************************************************************
3745 * MonitorFromPoint (USER32.@)
3747 HMONITOR WINAPI MonitorFromPoint( POINT pt, DWORD flags )
3749 RECT rect;
3751 SetRect( &rect, pt.x, pt.y, pt.x + 1, pt.y + 1 );
3752 return MonitorFromRect( &rect, flags );
3755 /***********************************************************************
3756 * MonitorFromWindow (USER32.@)
3758 HMONITOR WINAPI MonitorFromWindow(HWND hWnd, DWORD dwFlags)
3760 RECT rect;
3761 WINDOWPLACEMENT wp;
3763 TRACE("(%p, 0x%08x)\n", hWnd, dwFlags);
3765 wp.length = sizeof(wp);
3766 if (IsIconic(hWnd) && GetWindowPlacement(hWnd, &wp))
3767 return MonitorFromRect( &wp.rcNormalPosition, dwFlags );
3769 if (GetWindowRect( hWnd, &rect ))
3770 return MonitorFromRect( &rect, dwFlags );
3772 if (!(dwFlags & (MONITOR_DEFAULTTOPRIMARY|MONITOR_DEFAULTTONEAREST))) return 0;
3773 /* retrieve the primary */
3774 SetRect( &rect, 0, 0, 1, 1 );
3775 return MonitorFromRect( &rect, dwFlags );
3778 /* Return FALSE on failure and TRUE on success */
3779 static BOOL update_monitor_cache(void)
3781 SP_DEVINFO_DATA device_data = {sizeof(device_data)};
3782 HDEVINFO devinfo = INVALID_HANDLE_VALUE;
3783 MONITORINFOEXW *monitor_array;
3784 FILETIME filetime = {0};
3785 DWORD device_count = 0;
3786 HANDLE mutex = NULL;
3787 DWORD state_flags;
3788 BOOL ret = FALSE;
3789 BOOL is_replica;
3790 DWORD i = 0, j;
3791 DWORD type;
3793 /* Update monitor cache from SetupAPI if it's outdated */
3794 if (!video_key && RegOpenKeyW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", &video_key ))
3795 return FALSE;
3796 if (RegQueryInfoKeyW( video_key, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &filetime ))
3797 return FALSE;
3798 if (CompareFileTime( &filetime, &last_query_monitors_time ) < 1)
3799 return TRUE;
3801 mutex = get_display_device_init_mutex();
3802 EnterCriticalSection( &monitors_section );
3803 devinfo = SetupDiGetClassDevsW( &GUID_DEVCLASS_MONITOR, L"DISPLAY", NULL, DIGCF_PRESENT );
3805 while (SetupDiEnumDeviceInfo( devinfo, i++, &device_data ))
3807 /* Inactive monitors don't get enumerated */
3808 if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, &type,
3809 (BYTE *)&state_flags, sizeof(DWORD), NULL, 0 ))
3810 goto fail;
3811 if (state_flags & DISPLAY_DEVICE_ACTIVE)
3812 device_count++;
3815 if (device_count && monitor_count < device_count)
3817 monitor_array = heap_alloc( device_count * sizeof(*monitor_array) );
3818 if (!monitor_array)
3819 goto fail;
3820 heap_free( monitors );
3821 monitors = monitor_array;
3824 for (i = 0, monitor_count = 0; SetupDiEnumDeviceInfo( devinfo, i, &device_data ); i++)
3826 if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, &type,
3827 (BYTE *)&state_flags, sizeof(DWORD), NULL, 0 ))
3828 goto fail;
3829 if (!(state_flags & DISPLAY_DEVICE_ACTIVE))
3830 continue;
3831 if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCMONITOR, &type,
3832 (BYTE *)&monitors[monitor_count].rcMonitor, sizeof(RECT), NULL, 0 ))
3833 goto fail;
3835 /* Replicas in mirroring monitor sets don't get enumerated */
3836 is_replica = FALSE;
3837 for (j = 0; j < monitor_count; j++)
3839 if (EqualRect(&monitors[j].rcMonitor, &monitors[monitor_count].rcMonitor))
3841 is_replica = TRUE;
3842 break;
3845 if (is_replica)
3846 continue;
3848 if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCWORK, &type,
3849 (BYTE *)&monitors[monitor_count].rcWork, sizeof(RECT), NULL, 0 ))
3850 goto fail;
3851 if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_ADAPTERNAME, &type,
3852 (BYTE *)monitors[monitor_count].szDevice, CCHDEVICENAME * sizeof(WCHAR), NULL, 0))
3853 goto fail;
3854 monitors[monitor_count].dwFlags =
3855 !wcscmp( L"\\\\.\\DISPLAY1", monitors[monitor_count].szDevice ) ? MONITORINFOF_PRIMARY : 0;
3857 monitor_count++;
3860 last_query_monitors_time = filetime;
3861 ret = TRUE;
3862 fail:
3863 SetupDiDestroyDeviceInfoList( devinfo );
3864 LeaveCriticalSection( &monitors_section );
3865 release_display_device_init_mutex( mutex );
3866 return ret;
3869 BOOL CDECL nulldrv_GetMonitorInfo( HMONITOR handle, MONITORINFO *info )
3871 UINT index = (UINT_PTR)handle - 1;
3873 TRACE("(%p, %p)\n", handle, info);
3875 /* Fallback to report one monitor */
3876 if (handle == NULLDRV_DEFAULT_HMONITOR)
3878 RECT default_rect = {0, 0, 640, 480};
3879 info->rcMonitor = default_rect;
3880 info->rcWork = default_rect;
3881 info->dwFlags = MONITORINFOF_PRIMARY;
3882 if (info->cbSize >= sizeof(MONITORINFOEXW))
3883 lstrcpyW( ((MONITORINFOEXW *)info)->szDevice, L"\\\\.\\DISPLAY1" );
3884 return TRUE;
3887 if (!update_monitor_cache())
3888 return FALSE;
3890 EnterCriticalSection( &monitors_section );
3891 if (index < monitor_count)
3893 info->rcMonitor = monitors[index].rcMonitor;
3894 info->rcWork = monitors[index].rcWork;
3895 info->dwFlags = monitors[index].dwFlags;
3896 if (info->cbSize >= sizeof(MONITORINFOEXW))
3897 lstrcpyW( ((MONITORINFOEXW *)info)->szDevice, monitors[index].szDevice );
3898 LeaveCriticalSection( &monitors_section );
3899 return TRUE;
3901 else
3903 LeaveCriticalSection( &monitors_section );
3904 SetLastError( ERROR_INVALID_MONITOR_HANDLE );
3905 return FALSE;
3909 /***********************************************************************
3910 * GetMonitorInfoA (USER32.@)
3912 BOOL WINAPI GetMonitorInfoA( HMONITOR monitor, LPMONITORINFO info )
3914 MONITORINFOEXW miW;
3915 BOOL ret;
3917 if (info->cbSize == sizeof(MONITORINFO)) return GetMonitorInfoW( monitor, info );
3918 if (info->cbSize != sizeof(MONITORINFOEXA)) return FALSE;
3920 miW.cbSize = sizeof(miW);
3921 ret = GetMonitorInfoW( monitor, (MONITORINFO *)&miW );
3922 if (ret)
3924 MONITORINFOEXA *miA = (MONITORINFOEXA *)info;
3925 miA->rcMonitor = miW.rcMonitor;
3926 miA->rcWork = miW.rcWork;
3927 miA->dwFlags = miW.dwFlags;
3928 WideCharToMultiByte(CP_ACP, 0, miW.szDevice, -1, miA->szDevice, sizeof(miA->szDevice), NULL, NULL);
3930 return ret;
3933 /***********************************************************************
3934 * GetMonitorInfoW (USER32.@)
3936 BOOL WINAPI GetMonitorInfoW( HMONITOR monitor, LPMONITORINFO info )
3938 BOOL ret;
3939 UINT dpi_from, dpi_to;
3941 if (info->cbSize != sizeof(MONITORINFOEXW) && info->cbSize != sizeof(MONITORINFO)) return FALSE;
3943 ret = USER_Driver->pGetMonitorInfo( monitor, info );
3944 if (ret)
3946 if ((dpi_to = get_thread_dpi()))
3948 dpi_from = get_monitor_dpi( monitor );
3949 info->rcMonitor = map_dpi_rect( info->rcMonitor, dpi_from, dpi_to );
3950 info->rcWork = map_dpi_rect( info->rcWork, dpi_from, dpi_to );
3952 TRACE( "flags %04x, monitor %s, work %s\n", info->dwFlags,
3953 wine_dbgstr_rect(&info->rcMonitor), wine_dbgstr_rect(&info->rcWork));
3955 return ret;
3958 struct enum_mon_data
3960 MONITORENUMPROC proc;
3961 LPARAM lparam;
3962 HDC hdc;
3963 POINT origin;
3964 RECT limit;
3967 #ifdef __i386__
3968 /* Some apps pass a non-stdcall callback to EnumDisplayMonitors,
3969 * so we need a small assembly wrapper to call it.
3970 * MJ's Help Diagnostic expects that %ecx contains the address to the rect.
3972 extern BOOL enum_mon_callback_wrapper( HMONITOR monitor, LPRECT rect, struct enum_mon_data *data );
3973 __ASM_GLOBAL_FUNC( enum_mon_callback_wrapper,
3974 "pushl %ebp\n\t"
3975 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
3976 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
3977 "movl %esp,%ebp\n\t"
3978 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
3979 "subl $8,%esp\n\t"
3980 "movl 16(%ebp),%eax\n\t" /* data */
3981 "movl 12(%ebp),%ecx\n\t" /* rect */
3982 "pushl 4(%eax)\n\t" /* data->lparam */
3983 "pushl %ecx\n\t" /* rect */
3984 "pushl 8(%eax)\n\t" /* data->hdc */
3985 "pushl 8(%ebp)\n\t" /* monitor */
3986 "call *(%eax)\n\t" /* data->proc */
3987 "leave\n\t"
3988 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
3989 __ASM_CFI(".cfi_same_value %ebp\n\t")
3990 "ret" )
3991 #endif /* __i386__ */
3993 static BOOL CALLBACK enum_mon_callback( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
3995 struct enum_mon_data *data = (struct enum_mon_data *)lp;
3996 RECT monrect = map_dpi_rect( *rect, get_monitor_dpi( monitor ), get_thread_dpi() );
3998 OffsetRect( &monrect, -data->origin.x, -data->origin.y );
3999 if (!IntersectRect( &monrect, &monrect, &data->limit )) return TRUE;
4000 #ifdef __i386__
4001 return enum_mon_callback_wrapper( monitor, &monrect, data );
4002 #else
4003 return data->proc( monitor, data->hdc, &monrect, data->lparam );
4004 #endif
4007 BOOL CDECL nulldrv_EnumDisplayMonitors( HDC hdc, RECT *rect, MONITORENUMPROC proc, LPARAM lp )
4009 RECT monitor_rect;
4010 DWORD i = 0;
4012 TRACE("(%p, %p, %p, 0x%lx)\n", hdc, rect, proc, lp);
4014 if (update_monitor_cache())
4016 while (TRUE)
4018 EnterCriticalSection( &monitors_section );
4019 if (i >= monitor_count)
4021 LeaveCriticalSection( &monitors_section );
4022 return TRUE;
4024 monitor_rect = monitors[i].rcMonitor;
4025 LeaveCriticalSection( &monitors_section );
4027 if (!proc( (HMONITOR)(UINT_PTR)(i + 1), hdc, &monitor_rect, lp ))
4028 return FALSE;
4030 ++i;
4034 /* Fallback to report one monitor if using SetupAPI failed */
4035 SetRect( &monitor_rect, 0, 0, 640, 480 );
4036 if (!proc( NULLDRV_DEFAULT_HMONITOR, hdc, &monitor_rect, lp ))
4037 return FALSE;
4038 return TRUE;
4041 /***********************************************************************
4042 * EnumDisplayMonitors (USER32.@)
4044 BOOL WINAPI EnumDisplayMonitors( HDC hdc, LPRECT rect, MONITORENUMPROC proc, LPARAM lp )
4046 struct enum_mon_data data;
4048 data.proc = proc;
4049 data.lparam = lp;
4050 data.hdc = hdc;
4052 if (hdc)
4054 if (!GetDCOrgEx( hdc, &data.origin )) return FALSE;
4055 if (GetClipBox( hdc, &data.limit ) == ERROR) return FALSE;
4057 else
4059 data.origin.x = data.origin.y = 0;
4060 data.limit.left = data.limit.top = INT_MIN;
4061 data.limit.right = data.limit.bottom = INT_MAX;
4063 if (rect && !IntersectRect( &data.limit, &data.limit, rect )) return TRUE;
4064 return USER_Driver->pEnumDisplayMonitors( 0, NULL, enum_mon_callback, (LPARAM)&data );
4067 /***********************************************************************
4068 * EnumDisplayDevicesA (USER32.@)
4070 BOOL WINAPI EnumDisplayDevicesA( LPCSTR device, DWORD index, DISPLAY_DEVICEA *info, DWORD flags )
4072 UNICODE_STRING deviceW;
4073 DISPLAY_DEVICEW ddW;
4074 BOOL ret;
4076 if (device)
4077 RtlCreateUnicodeStringFromAsciiz( &deviceW, device );
4078 else
4079 deviceW.Buffer = NULL;
4081 ddW.cb = sizeof(ddW);
4082 ret = EnumDisplayDevicesW( deviceW.Buffer, index, &ddW, flags );
4083 RtlFreeUnicodeString( &deviceW );
4085 if (!ret)
4086 return ret;
4088 WideCharToMultiByte( CP_ACP, 0, ddW.DeviceName, -1, info->DeviceName, sizeof(info->DeviceName), NULL, NULL );
4089 WideCharToMultiByte( CP_ACP, 0, ddW.DeviceString, -1, info->DeviceString, sizeof(info->DeviceString), NULL, NULL );
4090 info->StateFlags = ddW.StateFlags;
4092 if (info->cb >= offsetof(DISPLAY_DEVICEA, DeviceID) + sizeof(info->DeviceID))
4093 WideCharToMultiByte( CP_ACP, 0, ddW.DeviceID, -1, info->DeviceID, sizeof(info->DeviceID), NULL, NULL );
4094 if (info->cb >= offsetof(DISPLAY_DEVICEA, DeviceKey) + sizeof(info->DeviceKey))
4095 WideCharToMultiByte( CP_ACP, 0, ddW.DeviceKey, -1, info->DeviceKey, sizeof(info->DeviceKey), NULL, NULL );
4097 return TRUE;
4100 /***********************************************************************
4101 * EnumDisplayDevicesW (USER32.@)
4103 BOOL WINAPI EnumDisplayDevicesW( LPCWSTR device, DWORD index, DISPLAY_DEVICEW *info, DWORD flags )
4105 SP_DEVINFO_DATA device_data = {sizeof(device_data)};
4106 HDEVINFO set = INVALID_HANDLE_VALUE;
4107 WCHAR key_nameW[MAX_PATH];
4108 WCHAR instanceW[MAX_PATH];
4109 WCHAR bufferW[1024];
4110 LONG adapter_index;
4111 WCHAR *next_charW;
4112 HANDLE mutex;
4113 DWORD size;
4114 DWORD type;
4115 HKEY hkey;
4116 BOOL ret = FALSE;
4118 TRACE("%s %d %p %#x\n", debugstr_w( device ), index, info, flags);
4120 wait_graphics_driver_ready();
4121 mutex = get_display_device_init_mutex();
4123 /* Find adapter */
4124 if (!device)
4126 swprintf( key_nameW, ARRAY_SIZE(key_nameW), L"\\Device\\Video%d", index );
4127 size = sizeof(bufferW);
4128 if (RegGetValueW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", key_nameW, RRF_RT_REG_SZ, NULL, bufferW, &size ))
4129 goto done;
4131 /* DeviceKey */
4132 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(info->DeviceKey))
4133 lstrcpyW( info->DeviceKey, bufferW );
4135 /* DeviceName */
4136 swprintf( info->DeviceName, ARRAY_SIZE(info->DeviceName), L"\\\\.\\DISPLAY%d", index + 1 );
4138 /* Strip \Registry\Machine\ */
4139 lstrcpyW( key_nameW, bufferW + 18 );
4141 /* DeviceString */
4142 size = sizeof(info->DeviceString);
4143 if (RegGetValueW( HKEY_LOCAL_MACHINE, key_nameW, L"DriverDesc", RRF_RT_REG_SZ, NULL,
4144 info->DeviceString, &size ))
4145 goto done;
4147 /* StateFlags */
4148 size = sizeof(info->StateFlags);
4149 if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, L"StateFlags", RRF_RT_REG_DWORD, NULL,
4150 &info->StateFlags, &size ))
4151 goto done;
4153 /* DeviceID */
4154 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->DeviceID))
4156 if (flags & EDD_GET_DEVICE_INTERFACE_NAME)
4157 info->DeviceID[0] = 0;
4158 else
4160 size = sizeof(bufferW);
4161 if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, L"GPUID", RRF_RT_REG_SZ | RRF_ZEROONFAILURE, NULL,
4162 bufferW, &size ))
4163 goto done;
4164 set = SetupDiCreateDeviceInfoList( &GUID_DEVCLASS_DISPLAY, NULL );
4165 if (!SetupDiOpenDeviceInfoW( set, bufferW, NULL, 0, &device_data )
4166 || !SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_HARDWAREID, NULL, (BYTE *)bufferW,
4167 sizeof(bufferW), NULL ))
4168 goto done;
4169 lstrcpyW( info->DeviceID, bufferW );
4173 /* Find monitor */
4174 else
4176 /* Check adapter name */
4177 if (wcsnicmp( device, L"\\\\.\\DISPLAY", lstrlenW(L"\\\\.\\DISPLAY") ))
4178 goto done;
4180 adapter_index = wcstol( device + lstrlenW(L"\\\\.\\DISPLAY"), NULL, 10 );
4181 swprintf( key_nameW, ARRAY_SIZE(key_nameW), L"\\Device\\Video%d", adapter_index - 1 );
4183 size = sizeof(bufferW);
4184 if (RegGetValueW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", key_nameW, RRF_RT_REG_SZ, NULL, bufferW, &size ))
4185 goto done;
4187 /* DeviceName */
4188 swprintf( info->DeviceName, ARRAY_SIZE(info->DeviceName), L"\\\\.\\DISPLAY%d\\Monitor%d", adapter_index, index );
4190 /* Get monitor instance */
4191 /* Strip \Registry\Machine\ first */
4192 lstrcpyW( key_nameW, bufferW + 18 );
4193 swprintf( bufferW, ARRAY_SIZE(bufferW), L"MonitorID%d", index );
4195 size = sizeof(instanceW);
4196 if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, bufferW, RRF_RT_REG_SZ, NULL, instanceW, &size ))
4197 goto done;
4199 set = SetupDiCreateDeviceInfoList( &GUID_DEVCLASS_MONITOR, NULL );
4200 if (!SetupDiOpenDeviceInfoW( set, instanceW, NULL, 0, &device_data ))
4201 goto done;
4203 /* StateFlags */
4204 if (!SetupDiGetDevicePropertyW( set, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, &type,
4205 (BYTE *)&info->StateFlags, sizeof(info->StateFlags), NULL, 0 ))
4206 goto done;
4208 /* DeviceString */
4209 if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_DEVICEDESC, NULL,
4210 (BYTE *)info->DeviceString,
4211 sizeof(info->DeviceString), NULL ))
4212 goto done;
4214 /* DeviceKey */
4215 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(info->DeviceKey))
4217 if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW,
4218 sizeof(bufferW), NULL ))
4219 goto done;
4221 lstrcpyW( info->DeviceKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\" );
4222 lstrcatW( info->DeviceKey, bufferW );
4225 /* DeviceID */
4226 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->DeviceID))
4228 if (flags & EDD_GET_DEVICE_INTERFACE_NAME)
4230 lstrcpyW( info->DeviceID, L"\\\\\?\\" );
4231 lstrcatW( info->DeviceID, instanceW );
4232 lstrcatW( info->DeviceID, L"#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}" );
4233 /* Replace '\\' with '#' after prefix */
4234 for (next_charW = info->DeviceID + lstrlenW( L"\\\\\?\\" ); *next_charW;
4235 next_charW++)
4237 if (*next_charW == '\\')
4238 *next_charW = '#';
4241 else
4243 if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_HARDWAREID, NULL, (BYTE *)bufferW,
4244 sizeof(bufferW), NULL ))
4245 goto done;
4247 lstrcpyW( info->DeviceID, bufferW );
4248 lstrcatW( info->DeviceID, L"\\" );
4250 if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW,
4251 sizeof(bufferW), NULL ))
4252 goto done;
4254 lstrcatW( info->DeviceID, bufferW );
4259 ret = TRUE;
4260 done:
4261 release_display_device_init_mutex( mutex );
4262 SetupDiDestroyDeviceInfoList( set );
4263 if (ret)
4264 return ret;
4266 /* Fallback to report at least one adapter and monitor, if user driver didn't initialize display device registry */
4267 if (index)
4268 return FALSE;
4270 /* If user driver did initialize the registry, then exit */
4271 if (!RegOpenKeyW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", &hkey ))
4273 RegCloseKey( hkey );
4274 return FALSE;
4276 WARN("Reporting fallback display devices\n");
4278 /* Adapter */
4279 if (!device)
4281 lstrcpyW( info->DeviceName, L"\\\\.\\DISPLAY1" );
4282 lstrcpyW( info->DeviceString, L"Wine Adapter" );
4283 info->StateFlags =
4284 DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_PRIMARY_DEVICE | DISPLAY_DEVICE_VGA_COMPATIBLE;
4285 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->DeviceID))
4287 if (flags & EDD_GET_DEVICE_INTERFACE_NAME)
4288 info->DeviceID[0] = 0;
4289 else
4290 lstrcpyW( info->DeviceID, L"PCI\\VEN_0000&DEV_0000&SUBSYS_00000000&REV_00" );
4293 /* Monitor */
4294 else
4296 if (lstrcmpiW( L"\\\\.\\DISPLAY1", device ))
4297 return FALSE;
4299 lstrcpyW( info->DeviceName, L"\\\\.\\DISPLAY1\\Monitor0" );
4300 lstrcpyW( info->DeviceString, L"Generic Non-PnP Monitor" );
4301 info->StateFlags = DISPLAY_DEVICE_ACTIVE | DISPLAY_DEVICE_ATTACHED;
4302 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->DeviceID))
4304 if (flags & EDD_GET_DEVICE_INTERFACE_NAME)
4305 lstrcpyW( info->DeviceID, L"\\\\\?\\DISPLAY#Default_Monitor#4&17f0ff54&0&UID0#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}" );
4306 else
4307 lstrcpyW( info->DeviceID, L"MONITOR\\Default_Monitor\\{4d36e96e-e325-11ce-bfc1-08002be10318}\\0000" );
4311 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(info->DeviceKey))
4312 info->DeviceKey[0] = 0;
4314 return TRUE;
4317 /**********************************************************************
4318 * GetAutoRotationState [USER32.@]
4320 BOOL WINAPI GetAutoRotationState( AR_STATE *state )
4322 TRACE("(%p)\n", state);
4324 if (!state)
4326 SetLastError(ERROR_INVALID_PARAMETER);
4327 return FALSE;
4330 *state = AR_NOSENSOR;
4331 return TRUE;
4334 /**********************************************************************
4335 * GetDisplayAutoRotationPreferences [USER32.@]
4337 BOOL WINAPI GetDisplayAutoRotationPreferences( ORIENTATION_PREFERENCE *orientation )
4339 FIXME("(%p): stub\n", orientation);
4340 *orientation = ORIENTATION_PREFERENCE_NONE;
4341 return TRUE;
4344 /* physical<->logical mapping functions from win8 that are nops in later versions */
4346 /***********************************************************************
4347 * GetPhysicalCursorPos (USER32.@)
4349 BOOL WINAPI GetPhysicalCursorPos( POINT *point )
4351 return GetCursorPos( point );
4354 /***********************************************************************
4355 * SetPhysicalCursorPos (USER32.@)
4357 BOOL WINAPI SetPhysicalCursorPos( INT x, INT y )
4359 return SetCursorPos( x, y );
4362 /***********************************************************************
4363 * LogicalToPhysicalPoint (USER32.@)
4365 BOOL WINAPI LogicalToPhysicalPoint( HWND hwnd, POINT *point )
4367 return TRUE;
4370 /***********************************************************************
4371 * PhysicalToLogicalPoint (USER32.@)
4373 BOOL WINAPI PhysicalToLogicalPoint( HWND hwnd, POINT *point )
4375 return TRUE;
4378 /**********************************************************************
4379 * GetDisplayConfigBufferSizes (USER32.@)
4381 LONG WINAPI GetDisplayConfigBufferSizes(UINT32 flags, UINT32 *num_path_info, UINT32 *num_mode_info)
4383 LONG ret = ERROR_GEN_FAILURE;
4384 HANDLE mutex;
4385 HDEVINFO devinfo;
4386 SP_DEVINFO_DATA device_data = {sizeof(device_data)};
4387 DWORD monitor_index = 0, state_flags, type;
4389 FIXME("(0x%x %p %p): semi-stub\n", flags, num_path_info, num_mode_info);
4391 if (!num_path_info || !num_mode_info)
4392 return ERROR_INVALID_PARAMETER;
4394 *num_path_info = 0;
4396 if (flags != QDC_ALL_PATHS &&
4397 flags != QDC_ONLY_ACTIVE_PATHS &&
4398 flags != QDC_DATABASE_CURRENT)
4399 return ERROR_INVALID_PARAMETER;
4401 if (flags != QDC_ONLY_ACTIVE_PATHS)
4402 FIXME("only returning active paths\n");
4404 wait_graphics_driver_ready();
4405 mutex = get_display_device_init_mutex();
4407 /* Iterate through "targets"/monitors.
4408 * Each target corresponds to a path, and each path references a source and a target mode.
4410 devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, L"DISPLAY", NULL, DIGCF_PRESENT);
4411 if (devinfo == INVALID_HANDLE_VALUE)
4412 goto done;
4414 while (SetupDiEnumDeviceInfo(devinfo, monitor_index++, &device_data))
4416 /* Only count active monitors */
4417 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS,
4418 &type, (BYTE *)&state_flags, sizeof(state_flags), NULL, 0))
4419 goto done;
4421 if (state_flags & DISPLAY_DEVICE_ACTIVE)
4422 (*num_path_info)++;
4425 *num_mode_info = *num_path_info * 2;
4426 ret = ERROR_SUCCESS;
4427 TRACE("returning %u path(s) %u mode(s)\n", *num_path_info, *num_mode_info);
4429 done:
4430 SetupDiDestroyDeviceInfoList(devinfo);
4431 release_display_device_init_mutex(mutex);
4432 return ret;
4435 static DISPLAYCONFIG_ROTATION get_dc_rotation(const DEVMODEW *devmode)
4437 if (devmode->dmFields & DM_DISPLAYORIENTATION)
4438 return devmode->u1.s2.dmDisplayOrientation + 1;
4439 else
4440 return DISPLAYCONFIG_ROTATION_IDENTITY;
4443 static DISPLAYCONFIG_SCANLINE_ORDERING get_dc_scanline_ordering(const DEVMODEW *devmode)
4445 if (!(devmode->dmFields & DM_DISPLAYFLAGS))
4446 return DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED;
4447 else if (devmode->u2.dmDisplayFlags & DM_INTERLACED)
4448 return DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED;
4449 else
4450 return DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE;
4453 static DISPLAYCONFIG_PIXELFORMAT get_dc_pixelformat(DWORD dmBitsPerPel)
4455 if ((dmBitsPerPel == 8) || (dmBitsPerPel == 16) ||
4456 (dmBitsPerPel == 24) || (dmBitsPerPel == 32))
4457 return dmBitsPerPel / 8;
4458 else
4459 return DISPLAYCONFIG_PIXELFORMAT_NONGDI;
4462 static void set_mode_target_info(DISPLAYCONFIG_MODE_INFO *info, const LUID *gpu_luid, UINT32 target_id,
4463 UINT32 flags, const DEVMODEW *devmode)
4465 DISPLAYCONFIG_TARGET_MODE *mode = &(info->u.targetMode);
4467 info->infoType = DISPLAYCONFIG_MODE_INFO_TYPE_TARGET;
4468 info->adapterId = *gpu_luid;
4469 info->id = target_id;
4471 /* FIXME: Populate pixelRate/hSyncFreq/totalSize with real data */
4472 mode->targetVideoSignalInfo.pixelRate = devmode->dmDisplayFrequency * devmode->dmPelsWidth * devmode->dmPelsHeight;
4473 mode->targetVideoSignalInfo.hSyncFreq.Numerator = devmode->dmDisplayFrequency * devmode->dmPelsWidth;
4474 mode->targetVideoSignalInfo.hSyncFreq.Denominator = 1;
4475 mode->targetVideoSignalInfo.vSyncFreq.Numerator = devmode->dmDisplayFrequency;
4476 mode->targetVideoSignalInfo.vSyncFreq.Denominator = 1;
4477 mode->targetVideoSignalInfo.activeSize.cx = devmode->dmPelsWidth;
4478 mode->targetVideoSignalInfo.activeSize.cy = devmode->dmPelsHeight;
4479 if (flags & QDC_DATABASE_CURRENT)
4481 mode->targetVideoSignalInfo.totalSize.cx = 0;
4482 mode->targetVideoSignalInfo.totalSize.cy = 0;
4484 else
4486 mode->targetVideoSignalInfo.totalSize.cx = devmode->dmPelsWidth;
4487 mode->targetVideoSignalInfo.totalSize.cy = devmode->dmPelsHeight;
4489 mode->targetVideoSignalInfo.u.videoStandard = D3DKMDT_VSS_OTHER;
4490 mode->targetVideoSignalInfo.scanLineOrdering = get_dc_scanline_ordering(devmode);
4493 static void set_path_target_info(DISPLAYCONFIG_PATH_TARGET_INFO *info, const LUID *gpu_luid,
4494 UINT32 target_id, UINT32 mode_index, const DEVMODEW *devmode)
4496 info->adapterId = *gpu_luid;
4497 info->id = target_id;
4498 info->u.modeInfoIdx = mode_index;
4499 info->outputTechnology = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL;
4500 info->rotation = get_dc_rotation(devmode);
4501 info->scaling = DISPLAYCONFIG_SCALING_IDENTITY;
4502 info->refreshRate.Numerator = devmode->dmDisplayFrequency;
4503 info->refreshRate.Denominator = 1;
4504 info->scanLineOrdering = get_dc_scanline_ordering(devmode);
4505 info->targetAvailable = TRUE;
4506 info->statusFlags = DISPLAYCONFIG_TARGET_IN_USE;
4509 static void set_mode_source_info(DISPLAYCONFIG_MODE_INFO *info, const LUID *gpu_luid,
4510 UINT32 source_id, const DEVMODEW *devmode)
4512 DISPLAYCONFIG_SOURCE_MODE *mode = &(info->u.sourceMode);
4514 info->infoType = DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE;
4515 info->adapterId = *gpu_luid;
4516 info->id = source_id;
4518 mode->width = devmode->dmPelsWidth;
4519 mode->height = devmode->dmPelsHeight;
4520 mode->pixelFormat = get_dc_pixelformat(devmode->dmBitsPerPel);
4521 if (devmode->dmFields & DM_POSITION)
4523 mode->position = devmode->u1.s2.dmPosition;
4525 else
4527 mode->position.x = 0;
4528 mode->position.y = 0;
4532 static void set_path_source_info(DISPLAYCONFIG_PATH_SOURCE_INFO *info, const LUID *gpu_luid,
4533 UINT32 source_id, UINT32 mode_index)
4535 info->adapterId = *gpu_luid;
4536 info->id = source_id;
4537 info->u.modeInfoIdx = mode_index;
4538 info->statusFlags = DISPLAYCONFIG_SOURCE_IN_USE;
4541 static BOOL source_mode_exists(const DISPLAYCONFIG_MODE_INFO *modeinfo, UINT32 num_modes,
4542 UINT32 source_id, UINT32 *found_mode_index)
4544 UINT32 i;
4546 for (i = 0; i < num_modes; i++)
4548 if (modeinfo[i].infoType == DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE &&
4549 modeinfo[i].id == source_id)
4551 *found_mode_index = i;
4552 return TRUE;
4555 return FALSE;
4558 /***********************************************************************
4559 * QueryDisplayConfig (USER32.@)
4561 LONG WINAPI QueryDisplayConfig(UINT32 flags, UINT32 *numpathelements, DISPLAYCONFIG_PATH_INFO *pathinfo,
4562 UINT32 *numinfoelements, DISPLAYCONFIG_MODE_INFO *modeinfo,
4563 DISPLAYCONFIG_TOPOLOGY_ID *topologyid)
4565 LONG adapter_index, ret;
4566 HANDLE mutex;
4567 HDEVINFO devinfo;
4568 SP_DEVINFO_DATA device_data = {sizeof(device_data)};
4569 DWORD monitor_index = 0, state_flags, type;
4570 UINT32 output_id, source_mode_index, path_index = 0, mode_index = 0;
4571 LUID gpu_luid;
4572 WCHAR device_name[CCHDEVICENAME];
4573 DEVMODEW devmode;
4575 FIXME("(%08x %p %p %p %p %p): semi-stub\n", flags, numpathelements, pathinfo, numinfoelements, modeinfo, topologyid);
4577 if (!numpathelements || !numinfoelements)
4578 return ERROR_INVALID_PARAMETER;
4580 if (!*numpathelements || !*numinfoelements)
4581 return ERROR_INVALID_PARAMETER;
4583 if (flags != QDC_ALL_PATHS &&
4584 flags != QDC_ONLY_ACTIVE_PATHS &&
4585 flags != QDC_DATABASE_CURRENT)
4586 return ERROR_INVALID_PARAMETER;
4588 if (((flags == QDC_DATABASE_CURRENT) && !topologyid) ||
4589 ((flags != QDC_DATABASE_CURRENT) && topologyid))
4590 return ERROR_INVALID_PARAMETER;
4592 if (flags != QDC_ONLY_ACTIVE_PATHS)
4593 FIXME("only returning active paths\n");
4595 if (topologyid)
4597 FIXME("setting toplogyid to DISPLAYCONFIG_TOPOLOGY_INTERNAL\n");
4598 *topologyid = DISPLAYCONFIG_TOPOLOGY_INTERNAL;
4601 wait_graphics_driver_ready();
4602 mutex = get_display_device_init_mutex();
4604 /* Iterate through "targets"/monitors.
4605 * Each target corresponds to a path, and each path corresponds to one or two unique modes.
4607 devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, L"DISPLAY", NULL, DIGCF_PRESENT);
4608 if (devinfo == INVALID_HANDLE_VALUE)
4610 ret = ERROR_GEN_FAILURE;
4611 goto done;
4614 ret = ERROR_GEN_FAILURE;
4615 while (SetupDiEnumDeviceInfo(devinfo, monitor_index++, &device_data))
4617 /* Only count active monitors */
4618 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS,
4619 &type, (BYTE *)&state_flags, sizeof(state_flags), NULL, 0))
4620 goto done;
4621 if (!(state_flags & DISPLAY_DEVICE_ACTIVE))
4622 continue;
4624 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPROPKEY_MONITOR_GPU_LUID,
4625 &type, (BYTE *)&gpu_luid, sizeof(gpu_luid), NULL, 0))
4626 goto done;
4628 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPROPKEY_MONITOR_OUTPUT_ID,
4629 &type, (BYTE *)&output_id, sizeof(output_id), NULL, 0))
4630 goto done;
4632 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_ADAPTERNAME,
4633 &type, (BYTE *)device_name, sizeof(device_name), NULL, 0))
4634 goto done;
4636 memset(&devmode, 0, sizeof(devmode));
4637 devmode.dmSize = sizeof(devmode);
4638 if (!EnumDisplaySettingsW(device_name, ENUM_CURRENT_SETTINGS, &devmode))
4639 goto done;
4641 /* Extract the adapter index from device_name to use as the source ID */
4642 adapter_index = wcstol(device_name + lstrlenW(L"\\\\.\\DISPLAY"), NULL, 10);
4643 adapter_index--;
4645 if (path_index == *numpathelements || mode_index == *numinfoelements)
4647 ret = ERROR_INSUFFICIENT_BUFFER;
4648 goto done;
4651 pathinfo[path_index].flags = DISPLAYCONFIG_PATH_ACTIVE;
4652 set_mode_target_info(&modeinfo[mode_index], &gpu_luid, output_id, flags, &devmode);
4653 set_path_target_info(&(pathinfo[path_index].targetInfo), &gpu_luid, output_id, mode_index, &devmode);
4655 mode_index++;
4656 if (mode_index == *numinfoelements)
4658 ret = ERROR_INSUFFICIENT_BUFFER;
4659 goto done;
4662 /* Multiple targets can be driven by the same source, ensure a mode
4663 * hasn't already been added for this source.
4665 if (!source_mode_exists(modeinfo, mode_index, adapter_index, &source_mode_index))
4667 set_mode_source_info(&modeinfo[mode_index], &gpu_luid, adapter_index, &devmode);
4668 source_mode_index = mode_index;
4669 mode_index++;
4671 set_path_source_info(&(pathinfo[path_index].sourceInfo), &gpu_luid, adapter_index, source_mode_index);
4672 path_index++;
4675 *numpathelements = path_index;
4676 *numinfoelements = mode_index;
4677 ret = ERROR_SUCCESS;
4679 done:
4680 SetupDiDestroyDeviceInfoList(devinfo);
4681 release_display_device_init_mutex(mutex);
4682 return ret;
4685 /***********************************************************************
4686 * DisplayConfigGetDeviceInfo (USER32.@)
4688 LONG WINAPI DisplayConfigGetDeviceInfo(DISPLAYCONFIG_DEVICE_INFO_HEADER *packet)
4690 LONG ret = ERROR_GEN_FAILURE;
4691 HANDLE mutex;
4692 HDEVINFO devinfo;
4693 SP_DEVINFO_DATA device_data = {sizeof(device_data)};
4694 DWORD index = 0, type;
4695 LUID gpu_luid;
4697 TRACE("(%p)\n", packet);
4699 if (!packet || packet->size < sizeof(*packet))
4700 return ERROR_GEN_FAILURE;
4701 wait_graphics_driver_ready();
4703 switch (packet->type)
4705 case DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME:
4707 DISPLAYCONFIG_SOURCE_DEVICE_NAME *source_name = (DISPLAYCONFIG_SOURCE_DEVICE_NAME *)packet;
4708 WCHAR device_name[CCHDEVICENAME];
4709 LONG source_id;
4711 TRACE("DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME\n");
4713 if (packet->size < sizeof(*source_name))
4714 return ERROR_INVALID_PARAMETER;
4716 mutex = get_display_device_init_mutex();
4717 devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, L"DISPLAY", NULL, DIGCF_PRESENT);
4718 if (devinfo == INVALID_HANDLE_VALUE)
4720 release_display_device_init_mutex(mutex);
4721 return ret;
4724 while (SetupDiEnumDeviceInfo(devinfo, index++, &device_data))
4726 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPROPKEY_MONITOR_GPU_LUID,
4727 &type, (BYTE *)&gpu_luid, sizeof(gpu_luid), NULL, 0))
4728 continue;
4730 if ((source_name->header.adapterId.LowPart != gpu_luid.LowPart) ||
4731 (source_name->header.adapterId.HighPart != gpu_luid.HighPart))
4732 continue;
4734 /* QueryDisplayConfig() derives the source ID from the adapter name. */
4735 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_ADAPTERNAME,
4736 &type, (BYTE *)device_name, sizeof(device_name), NULL, 0))
4737 continue;
4739 source_id = wcstol(device_name + lstrlenW(L"\\\\.\\DISPLAY"), NULL, 10);
4740 source_id--;
4741 if (source_name->header.id != source_id)
4742 continue;
4744 lstrcpyW(source_name->viewGdiDeviceName, device_name);
4745 ret = ERROR_SUCCESS;
4746 break;
4748 SetupDiDestroyDeviceInfoList(devinfo);
4749 release_display_device_init_mutex(mutex);
4750 return ret;
4752 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME:
4754 DISPLAYCONFIG_TARGET_DEVICE_NAME *target_name = (DISPLAYCONFIG_TARGET_DEVICE_NAME *)packet;
4756 FIXME("DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME: stub\n");
4758 if (packet->size < sizeof(*target_name))
4759 return ERROR_INVALID_PARAMETER;
4761 return ERROR_NOT_SUPPORTED;
4763 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE:
4765 DISPLAYCONFIG_TARGET_PREFERRED_MODE *preferred_mode = (DISPLAYCONFIG_TARGET_PREFERRED_MODE *)packet;
4767 FIXME("DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE: stub\n");
4769 if (packet->size < sizeof(*preferred_mode))
4770 return ERROR_INVALID_PARAMETER;
4772 return ERROR_NOT_SUPPORTED;
4774 case DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME:
4776 DISPLAYCONFIG_ADAPTER_NAME *adapter_name = (DISPLAYCONFIG_ADAPTER_NAME *)packet;
4778 FIXME("DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME: stub\n");
4780 if (packet->size < sizeof(*adapter_name))
4781 return ERROR_INVALID_PARAMETER;
4783 return ERROR_NOT_SUPPORTED;
4785 case DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE:
4786 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE:
4787 case DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION:
4788 case DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION:
4789 case DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO:
4790 case DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE:
4791 case DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL:
4792 default:
4793 FIXME("Unimplemented packet type: %u\n", packet->type);
4794 return ERROR_INVALID_PARAMETER;
4798 /***********************************************************************
4799 * SetDisplayConfig (USER32.@)
4801 LONG WINAPI SetDisplayConfig(UINT32 path_info_count, DISPLAYCONFIG_PATH_INFO *path_info, UINT32 mode_info_count,
4802 DISPLAYCONFIG_MODE_INFO *mode_info, UINT32 flags)
4804 FIXME("path_info_count %u, path_info %p, mode_info_count %u, mode_info %p, flags %#x stub.\n",
4805 path_info_count, path_info, mode_info_count, mode_info, flags);
4807 return ERROR_SUCCESS;