winex11.drv: Update a comment.
[wine.git] / dlls / user32 / sysparams.c
blob1381f387e03d6a35eaab6a6359eee4093abeb75a
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) display_dc = CreateDCW( L"DISPLAY", NULL, NULL, NULL );
552 return display_dc;
555 void release_display_dc( HDC hdc )
557 LeaveCriticalSection( &display_dc_section );
560 static HANDLE get_display_device_init_mutex( void )
562 HANDLE mutex = CreateMutexW( NULL, FALSE, L"display_device_init" );
564 WaitForSingleObject( mutex, INFINITE );
565 return mutex;
568 static void release_display_device_init_mutex( HANDLE mutex )
570 ReleaseMutex( mutex );
571 CloseHandle( mutex );
574 /* Wait until graphics driver is loaded by explorer */
575 static void wait_graphics_driver_ready(void)
577 static BOOL ready = FALSE;
579 if (!ready)
581 SendMessageW( GetDesktopWindow(), WM_NULL, 0, 0 );
582 ready = TRUE;
586 /* map value from system dpi to standard 96 dpi for storing in the registry */
587 static int map_from_system_dpi( int val )
589 return MulDiv( val, USER_DEFAULT_SCREEN_DPI, GetDpiForSystem() );
592 /* map value from 96 dpi to system or custom dpi */
593 static int map_to_dpi( int val, UINT dpi )
595 if (!dpi) dpi = GetDpiForSystem();
596 return MulDiv( val, dpi, USER_DEFAULT_SCREEN_DPI );
599 static INT CALLBACK real_fontname_proc(const LOGFONTW *lf, const TEXTMETRICW *ntm, DWORD type, LPARAM lparam)
601 const ENUMLOGFONTW *elf = (const ENUMLOGFONTW *)lf;
602 WCHAR *fullname = (WCHAR *)lparam;
604 lstrcpynW( fullname, elf->elfFullName, LF_FACESIZE );
605 return 0;
608 static void get_real_fontname( LOGFONTW *lf, WCHAR fullname[LF_FACESIZE] )
610 HDC hdc = get_display_dc();
611 lstrcpyW( fullname, lf->lfFaceName );
612 EnumFontFamiliesExW( hdc, lf, real_fontname_proc, (LPARAM)fullname, 0 );
613 release_display_dc( hdc );
616 /* adjust some of the raw values found in the registry */
617 static void normalize_nonclientmetrics( NONCLIENTMETRICSW *pncm)
619 TEXTMETRICW tm;
620 HDC hdc = get_display_dc();
622 if( pncm->iBorderWidth < 1) pncm->iBorderWidth = 1;
623 if( pncm->iCaptionWidth < 8) pncm->iCaptionWidth = 8;
624 if( pncm->iScrollWidth < 8) pncm->iScrollWidth = 8;
625 if( pncm->iScrollHeight < 8) pncm->iScrollHeight = 8;
627 /* adjust some heights to the corresponding font */
628 get_text_metr_size( hdc, &pncm->lfMenuFont, &tm, NULL);
629 pncm->iMenuHeight = max( pncm->iMenuHeight, 2 + tm.tmHeight + tm.tmExternalLeading );
630 get_text_metr_size( hdc, &pncm->lfCaptionFont, &tm, NULL);
631 pncm->iCaptionHeight = max( pncm->iCaptionHeight, 2 + tm.tmHeight);
632 get_text_metr_size( hdc, &pncm->lfSmCaptionFont, &tm, NULL);
633 pncm->iSmCaptionHeight = max( pncm->iSmCaptionHeight, 2 + tm.tmHeight);
634 release_display_dc( hdc );
637 static BOOL CALLBACK enum_monitors( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
639 MONITORINFO mi;
641 mi.cbSize = sizeof(mi);
642 if (GetMonitorInfoW( monitor, &mi ) && (mi.dwFlags & MONITORINFOF_PRIMARY))
644 LPRECT work = (LPRECT)lp;
645 *work = mi.rcWork;
646 return FALSE;
648 return TRUE;
651 /* load a uint parameter from the registry */
652 static BOOL get_uint_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
654 if (!ptr_param) return FALSE;
656 if (!entry->hdr.loaded)
658 WCHAR buf[32];
660 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->uint.val = wcstol( buf, NULL, 10 );
662 *(UINT *)ptr_param = entry->uint.val;
663 return TRUE;
666 /* set a uint parameter in the registry */
667 static BOOL set_uint_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
669 WCHAR buf[32];
671 wsprintfW( buf, L"%u", int_param );
672 if (!save_entry_string( &entry->hdr, buf, flags )) return FALSE;
673 entry->uint.val = int_param;
674 entry->hdr.loaded = TRUE;
675 return TRUE;
678 /* initialize a uint parameter */
679 static BOOL init_uint_entry( union sysparam_all_entry *entry )
681 WCHAR buf[32];
683 wsprintfW( buf, L"%u", entry->uint.val );
684 return init_entry_string( &entry->hdr, buf );
687 /* set an int parameter in the registry */
688 static BOOL set_int_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
690 WCHAR buf[32];
692 wsprintfW( buf, L"%d", int_param );
693 if (!save_entry_string( &entry->hdr, buf, flags )) return FALSE;
694 entry->uint.val = int_param;
695 entry->hdr.loaded = TRUE;
696 return TRUE;
699 /* initialize an int parameter */
700 static BOOL init_int_entry( union sysparam_all_entry *entry )
702 WCHAR buf[32];
704 wsprintfW( buf, L"%d", entry->uint.val );
705 return init_entry_string( &entry->hdr, buf );
708 /* load a twips parameter from the registry */
709 static BOOL get_twips_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
711 int val;
713 if (!ptr_param) return FALSE;
715 if (!entry->hdr.loaded)
717 WCHAR buf[32];
719 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->uint.val = wcstol( buf, NULL, 10 );
722 /* Dimensions are quoted as being "twips" values if negative and pixels if positive.
723 * One inch is 1440 twips.
724 * See for example
725 * Technical Reference to the Windows 2000 Registry ->
726 * HKEY_CURRENT_USER -> Control Panel -> Desktop -> WindowMetrics
728 val = entry->uint.val;
729 if (val < 0)
730 val = MulDiv( -val, dpi, 1440 );
731 else
732 val = map_to_dpi( val, dpi );
734 *(int *)ptr_param = val;
735 return TRUE;
738 /* set a twips parameter in the registry */
739 static BOOL set_twips_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
741 int val = int_param;
742 if (val > 0) val = map_from_system_dpi( val );
743 return set_int_entry( entry, val, ptr_param, flags );
746 /* load a bool parameter from the registry */
747 static BOOL get_bool_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
749 if (!ptr_param) return FALSE;
751 if (!entry->hdr.loaded)
753 WCHAR buf[32];
755 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->bool.val = wcstol( buf, NULL, 10 ) != 0;
757 *(UINT *)ptr_param = entry->bool.val;
758 return TRUE;
761 /* set a bool parameter in the registry */
762 static BOOL set_bool_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
764 WCHAR buf[32];
766 wsprintfW( buf, L"%u", int_param != 0 );
767 if (!save_entry_string( &entry->hdr, buf, flags )) return FALSE;
768 entry->bool.val = int_param != 0;
769 entry->hdr.loaded = TRUE;
770 return TRUE;
773 /* initialize a bool parameter */
774 static BOOL init_bool_entry( union sysparam_all_entry *entry )
776 WCHAR buf[32];
778 wsprintfW( buf, L"%u", entry->bool.val != 0 );
779 return init_entry_string( &entry->hdr, buf );
782 /* load a bool parameter using Yes/No strings from the registry */
783 static BOOL get_yesno_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
785 if (!ptr_param) return FALSE;
787 if (!entry->hdr.loaded)
789 WCHAR buf[32];
791 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->bool.val = !lstrcmpiW( L"Yes", buf );
793 *(UINT *)ptr_param = entry->bool.val;
794 return TRUE;
797 /* set a bool parameter using Yes/No strings from the registry */
798 static BOOL set_yesno_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
800 const WCHAR *str = int_param ? L"Yes" : L"No";
802 if (!save_entry_string( &entry->hdr, str, flags )) return FALSE;
803 entry->bool.val = int_param != 0;
804 entry->hdr.loaded = TRUE;
805 return TRUE;
808 /* initialize a bool parameter using Yes/No strings */
809 static BOOL init_yesno_entry( union sysparam_all_entry *entry )
811 return init_entry_string( &entry->hdr, entry->bool.val ? L"Yes" : L"No" );
814 /* load a dword (binary) parameter from the registry */
815 static BOOL get_dword_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
817 if (!ptr_param) return FALSE;
819 if (!entry->hdr.loaded)
821 DWORD val;
822 if (load_entry( &entry->hdr, &val, sizeof(val) ) == sizeof(DWORD)) entry->dword.val = val;
824 *(DWORD *)ptr_param = entry->dword.val;
825 return TRUE;
828 /* set a dword (binary) parameter in the registry */
829 static BOOL set_dword_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
831 DWORD val = PtrToUlong( ptr_param );
833 if (!save_entry( &entry->hdr, &val, sizeof(val), REG_DWORD, flags )) return FALSE;
834 entry->dword.val = val;
835 entry->hdr.loaded = TRUE;
836 return TRUE;
839 /* initialize a dword parameter */
840 static BOOL init_dword_entry( union sysparam_all_entry *entry )
842 return init_entry( &entry->hdr, &entry->dword.val, sizeof(entry->dword.val), REG_DWORD );
845 /* load an RGB parameter from the registry */
846 static BOOL get_rgb_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
848 if (!ptr_param) return FALSE;
850 if (!entry->hdr.loaded)
852 WCHAR buf[32];
854 if (load_entry( &entry->hdr, buf, sizeof(buf) ))
856 DWORD r, g, b;
857 WCHAR *end, *str = buf;
859 r = wcstoul( str, &end, 10 );
860 if (end == str || !*end) goto done;
861 str = end + 1;
862 g = wcstoul( str, &end, 10 );
863 if (end == str || !*end) goto done;
864 str = end + 1;
865 b = wcstoul( str, &end, 10 );
866 if (end == str) goto done;
867 if (r > 255 || g > 255 || b > 255) goto done;
868 entry->rgb.val = RGB( r, g, b );
871 done:
872 *(COLORREF *)ptr_param = entry->rgb.val;
873 return TRUE;
876 /* set an RGB parameter in the registry */
877 static BOOL set_rgb_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
879 WCHAR buf[32];
880 HBRUSH brush;
881 HPEN pen;
883 wsprintfW( buf, L"%u %u %u", GetRValue(int_param), GetGValue(int_param), GetBValue(int_param) );
884 if (!save_entry_string( &entry->hdr, buf, flags )) return FALSE;
885 entry->rgb.val = int_param;
886 entry->hdr.loaded = TRUE;
887 if ((brush = InterlockedExchangePointer( (void **)&entry->rgb.brush, 0 )))
889 __wine_make_gdi_object_system( brush, FALSE );
890 DeleteObject( brush );
892 if ((pen = InterlockedExchangePointer( (void **)&entry->rgb.pen, 0 )))
894 __wine_make_gdi_object_system( pen, FALSE );
895 DeleteObject( pen );
897 return TRUE;
900 /* initialize an RGB parameter */
901 static BOOL init_rgb_entry( union sysparam_all_entry *entry )
903 WCHAR buf[32];
905 wsprintfW( buf, L"%u %u %u", GetRValue(entry->rgb.val), GetGValue(entry->rgb.val), GetBValue(entry->rgb.val) );
906 return init_entry_string( &entry->hdr, buf );
909 /* load a font (binary) parameter from the registry */
910 static BOOL get_font_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
912 LOGFONTW font;
914 if (!ptr_param) return FALSE;
916 if (!entry->hdr.loaded)
918 switch (load_entry( &entry->hdr, &font, sizeof(font) ))
920 case sizeof(font):
921 if (font.lfHeight > 0) /* positive height value means points ( inch/72 ) */
922 font.lfHeight = -MulDiv( font.lfHeight, USER_DEFAULT_SCREEN_DPI, 72 );
923 entry->font.val = font;
924 break;
925 case sizeof(LOGFONT16): /* win9x-winME format */
926 SYSPARAMS_LogFont16To32W( (LOGFONT16 *)&font, &entry->font.val );
927 if (entry->font.val.lfHeight > 0)
928 entry->font.val.lfHeight = -MulDiv( entry->font.val.lfHeight, USER_DEFAULT_SCREEN_DPI, 72 );
929 break;
930 default:
931 WARN( "Unknown format in key %s value %s\n",
932 debugstr_w( parameter_key_names[entry->hdr.base_key] ),
933 debugstr_w( entry->hdr.regval ));
934 /* fall through */
935 case 0: /* use the default GUI font */
936 GetObjectW( GetStockObject( DEFAULT_GUI_FONT ), sizeof(font), &font );
937 font.lfHeight = map_from_system_dpi( font.lfHeight );
938 font.lfWeight = entry->font.weight;
939 entry->font.val = font;
940 break;
942 get_real_fontname( &entry->font.val, entry->font.fullname );
943 entry->hdr.loaded = TRUE;
945 font = entry->font.val;
946 font.lfHeight = map_to_dpi( font.lfHeight, dpi );
947 lstrcpyW( font.lfFaceName, entry->font.fullname );
948 *(LOGFONTW *)ptr_param = font;
949 return TRUE;
952 /* set a font (binary) parameter in the registry */
953 static BOOL set_font_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
955 LOGFONTW font;
956 WCHAR *ptr;
958 memcpy( &font, ptr_param, sizeof(font) );
959 /* zero pad the end of lfFaceName so we don't save uninitialised data */
960 ptr = wmemchr( font.lfFaceName, 0, LF_FACESIZE );
961 if (ptr) memset( ptr, 0, (font.lfFaceName + LF_FACESIZE - ptr) * sizeof(WCHAR) );
962 if (font.lfHeight < 0) font.lfHeight = map_from_system_dpi( font.lfHeight );
964 if (!save_entry( &entry->hdr, &font, sizeof(font), REG_BINARY, flags )) return FALSE;
965 entry->font.val = font;
966 get_real_fontname( &entry->font.val, entry->font.fullname );
967 entry->hdr.loaded = TRUE;
968 return TRUE;
971 /* initialize a font (binary) parameter */
972 static BOOL init_font_entry( union sysparam_all_entry *entry )
974 GetObjectW( GetStockObject( DEFAULT_GUI_FONT ), sizeof(entry->font.val), &entry->font.val );
975 entry->font.val.lfHeight = map_from_system_dpi( entry->font.val.lfHeight );
976 entry->font.val.lfWeight = entry->font.weight;
977 get_real_fontname( &entry->font.val, entry->font.fullname );
978 return init_entry( &entry->hdr, &entry->font.val, sizeof(entry->font.val), REG_BINARY );
981 /* get a path parameter in the registry */
982 static BOOL get_path_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
984 if (!ptr_param) return FALSE;
986 if (!entry->hdr.loaded)
988 WCHAR buffer[MAX_PATH];
990 if (load_entry( &entry->hdr, buffer, sizeof(buffer) ))
991 lstrcpynW( entry->path.path, buffer, MAX_PATH );
993 lstrcpynW( ptr_param, entry->path.path, int_param );
994 return TRUE;
997 /* set a path parameter in the registry */
998 static BOOL set_path_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
1000 WCHAR buffer[MAX_PATH];
1001 BOOL ret;
1003 lstrcpynW( buffer, ptr_param, MAX_PATH );
1004 ret = save_entry_string( &entry->hdr, buffer, flags );
1005 if (ret)
1007 lstrcpyW( entry->path.path, buffer );
1008 entry->hdr.loaded = TRUE;
1010 return ret;
1013 /* initialize a path parameter */
1014 static BOOL init_path_entry( union sysparam_all_entry *entry )
1016 return init_entry_string( &entry->hdr, entry->path.path );
1019 /* get a binary parameter in the registry */
1020 static BOOL get_binary_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
1022 if (!ptr_param) return FALSE;
1024 if (!entry->hdr.loaded)
1026 void *buffer = HeapAlloc( GetProcessHeap(), 0, entry->bin.size );
1027 DWORD len = load_entry( &entry->hdr, buffer, entry->bin.size );
1029 if (len)
1031 memcpy( entry->bin.ptr, buffer, entry->bin.size );
1032 memset( (char *)entry->bin.ptr + len, 0, entry->bin.size - len );
1034 HeapFree( GetProcessHeap(), 0, buffer );
1036 memcpy( ptr_param, entry->bin.ptr, min( int_param, entry->bin.size ) );
1037 return TRUE;
1040 /* set a binary parameter in the registry */
1041 static BOOL set_binary_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
1043 BOOL ret;
1044 void *buffer = HeapAlloc( GetProcessHeap(), 0, entry->bin.size );
1046 memcpy( buffer, entry->bin.ptr, entry->bin.size );
1047 memcpy( buffer, ptr_param, min( int_param, entry->bin.size ));
1048 ret = save_entry( &entry->hdr, buffer, entry->bin.size, REG_BINARY, flags );
1049 if (ret)
1051 memcpy( entry->bin.ptr, buffer, entry->bin.size );
1052 entry->hdr.loaded = TRUE;
1054 HeapFree( GetProcessHeap(), 0, buffer );
1055 return ret;
1058 /* initialize a binary parameter */
1059 static BOOL init_binary_entry( union sysparam_all_entry *entry )
1061 return init_entry( &entry->hdr, entry->bin.ptr, entry->bin.size, REG_BINARY );
1064 /* get a user pref parameter in the registry */
1065 static BOOL get_userpref_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
1067 union sysparam_all_entry *parent_entry = (union sysparam_all_entry *)entry->pref.parent;
1068 BYTE prefs[8];
1070 if (!ptr_param) return FALSE;
1072 if (!parent_entry->hdr.get( parent_entry, sizeof(prefs), prefs, dpi )) return FALSE;
1073 *(BOOL *)ptr_param = (prefs[entry->pref.offset] & entry->pref.mask) != 0;
1074 return TRUE;
1077 /* set a user pref parameter in the registry */
1078 static BOOL set_userpref_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
1080 union sysparam_all_entry *parent_entry = (union sysparam_all_entry *)entry->pref.parent;
1081 BYTE prefs[8];
1083 parent_entry->hdr.loaded = FALSE; /* force loading it again */
1084 if (!parent_entry->hdr.get( parent_entry, sizeof(prefs), prefs, GetDpiForSystem() )) return FALSE;
1086 if (PtrToUlong( ptr_param )) prefs[entry->pref.offset] |= entry->pref.mask;
1087 else prefs[entry->pref.offset] &= ~entry->pref.mask;
1089 return parent_entry->hdr.set( parent_entry, sizeof(prefs), prefs, flags );
1092 static BOOL get_entry_dpi( void *ptr, UINT int_param, void *ptr_param, UINT dpi )
1094 union sysparam_all_entry *entry = ptr;
1095 return entry->hdr.get( entry, int_param, ptr_param, dpi );
1098 static BOOL get_entry( void *ptr, UINT int_param, void *ptr_param )
1100 return get_entry_dpi( ptr, int_param, ptr_param, GetDpiForSystem() );
1103 static BOOL set_entry( void *ptr, UINT int_param, void *ptr_param, UINT flags )
1105 union sysparam_all_entry *entry = ptr;
1106 return entry->hdr.set( entry, int_param, ptr_param, flags );
1109 #define UINT_ENTRY(name,val,base,reg) \
1110 struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_uint_entry, init_uint_entry, \
1111 base, reg }, (val) }
1113 #define UINT_ENTRY_MIRROR(name,val,base,reg,mirror_base) \
1114 struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_uint_entry, init_uint_entry, \
1115 base, reg, mirror_base, reg }, (val) }
1117 #define INT_ENTRY(name,val,base,reg) \
1118 struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_int_entry, init_int_entry, \
1119 base, reg }, (val) }
1121 #define BOOL_ENTRY(name,val,base,reg) \
1122 struct sysparam_bool_entry entry_##name = { { get_bool_entry, set_bool_entry, init_bool_entry, \
1123 base, reg }, (val) }
1125 #define BOOL_ENTRY_MIRROR(name,val,base,reg,mirror_base) \
1126 struct sysparam_bool_entry entry_##name = { { get_bool_entry, set_bool_entry, init_bool_entry, \
1127 base, reg, mirror_base, reg }, (val) }
1129 #define YESNO_ENTRY(name,val,base,reg) \
1130 struct sysparam_bool_entry entry_##name = { { get_yesno_entry, set_yesno_entry, init_yesno_entry, \
1131 base, reg }, (val) }
1133 #define TWIPS_ENTRY(name,val,base,reg) \
1134 struct sysparam_uint_entry entry_##name = { { get_twips_entry, set_twips_entry, init_int_entry, \
1135 base, reg }, (val) }
1137 #define DWORD_ENTRY(name,val,base,reg) \
1138 struct sysparam_dword_entry entry_##name = { { get_dword_entry, set_dword_entry, init_dword_entry, \
1139 base, reg }, (val) }
1141 #define BINARY_ENTRY(name,data,base,reg) \
1142 struct sysparam_binary_entry entry_##name = { { get_binary_entry, set_binary_entry, init_binary_entry, \
1143 base, reg }, data, sizeof(data) }
1145 #define PATH_ENTRY(name,base,reg) \
1146 struct sysparam_path_entry entry_##name = { { get_path_entry, set_path_entry, init_path_entry, \
1147 base, reg } }
1149 #define FONT_ENTRY(name,weight,base,reg) \
1150 struct sysparam_font_entry entry_##name = { { get_font_entry, set_font_entry, init_font_entry, \
1151 base, reg }, (weight) }
1153 #define USERPREF_ENTRY(name,offset,mask) \
1154 struct sysparam_pref_entry entry_##name = { { get_userpref_entry, set_userpref_entry }, \
1155 &entry_USERPREFERENCESMASK, (offset), (mask) }
1157 static UINT_ENTRY( DRAGWIDTH, 4, DESKTOP_KEY, L"DragWidth" );
1158 static UINT_ENTRY( DRAGHEIGHT, 4, DESKTOP_KEY, L"DragHeight" );
1159 static UINT_ENTRY( DOUBLECLICKTIME, 500, MOUSE_KEY, L"DoubleClickSpeed" );
1160 static UINT_ENTRY( FONTSMOOTHING, 2, DESKTOP_KEY, L"FontSmoothing" );
1161 static UINT_ENTRY( GRIDGRANULARITY, 0, DESKTOP_KEY, L"GridGranularity" );
1162 static UINT_ENTRY( KEYBOARDDELAY, 1, KEYBOARD_KEY, L"KeyboardDelay" );
1163 static UINT_ENTRY( KEYBOARDSPEED, 31, KEYBOARD_KEY, L"KeyboardSpeed" );
1164 static UINT_ENTRY( MENUSHOWDELAY, 400, DESKTOP_KEY, L"MenuShowDelay" );
1165 static UINT_ENTRY( MINARRANGE, ARW_HIDE, METRICS_KEY, L"MinArrange" );
1166 static UINT_ENTRY( MINHORZGAP, 0, METRICS_KEY, L"MinHorzGap" );
1167 static UINT_ENTRY( MINVERTGAP, 0, METRICS_KEY, L"MinVertGap" );
1168 static UINT_ENTRY( MINWIDTH, 154, METRICS_KEY, L"MinWidth" );
1169 static UINT_ENTRY( MOUSEHOVERHEIGHT, 4, MOUSE_KEY, L"MouseHoverHeight" );
1170 static UINT_ENTRY( MOUSEHOVERTIME, 400, MOUSE_KEY, L"MouseHoverTime" );
1171 static UINT_ENTRY( MOUSEHOVERWIDTH, 4, MOUSE_KEY, L"MouseHoverWidth" );
1172 static UINT_ENTRY( MOUSESPEED, 10, MOUSE_KEY, L"MouseSensitivity" );
1173 static UINT_ENTRY( MOUSETRAILS, 0, MOUSE_KEY, L"MouseTrails" );
1174 static UINT_ENTRY( SCREENSAVETIMEOUT, 300, DESKTOP_KEY, L"ScreenSaveTimeOut" );
1175 static UINT_ENTRY( WHEELSCROLLCHARS, 3, DESKTOP_KEY, L"WheelScrollChars" );
1176 static UINT_ENTRY( WHEELSCROLLLINES, 3, DESKTOP_KEY, L"WheelScrollLines" );
1177 static UINT_ENTRY_MIRROR( DOUBLECLKHEIGHT, 4, MOUSE_KEY, L"DoubleClickHeight", DESKTOP_KEY );
1178 static UINT_ENTRY_MIRROR( DOUBLECLKWIDTH, 4, MOUSE_KEY, L"DoubleClickWidth", DESKTOP_KEY );
1179 static UINT_ENTRY_MIRROR( MENUDROPALIGNMENT, 0, DESKTOP_KEY, L"MenuDropAlignment", VERSION_KEY );
1181 static INT_ENTRY( MOUSETHRESHOLD1, 6, MOUSE_KEY, L"MouseThreshold1" );
1182 static INT_ENTRY( MOUSETHRESHOLD2, 10, MOUSE_KEY, L"MouseThreshold2" );
1183 static INT_ENTRY( MOUSEACCELERATION, 1, MOUSE_KEY, L"MouseSpeed" );
1185 static BOOL_ENTRY( BLOCKSENDINPUTRESETS, FALSE, DESKTOP_KEY, L"BlockSendInputResets" );
1186 static BOOL_ENTRY( DRAGFULLWINDOWS, FALSE, DESKTOP_KEY, L"DragFullWindows" );
1187 static BOOL_ENTRY( KEYBOARDPREF, TRUE, KEYBOARDPREF_KEY, L"On" );
1188 static BOOL_ENTRY( LOWPOWERACTIVE, FALSE, DESKTOP_KEY, L"LowPowerActive" );
1189 static BOOL_ENTRY( MOUSEBUTTONSWAP, FALSE, MOUSE_KEY, L"SwapMouseButtons" );
1190 static BOOL_ENTRY( POWEROFFACTIVE, FALSE, DESKTOP_KEY, L"PowerOffActive" );
1191 static BOOL_ENTRY( SCREENREADER, FALSE, SCREENREADER_KEY, L"On" );
1192 static BOOL_ENTRY( SCREENSAVEACTIVE, TRUE, DESKTOP_KEY, L"ScreenSaveActive" );
1193 static BOOL_ENTRY( SCREENSAVERRUNNING, FALSE, DESKTOP_KEY, L"WINE_ScreenSaverRunning" ); /* FIXME - real value */
1194 static BOOL_ENTRY( SHOWSOUNDS, FALSE, SHOWSOUNDS_KEY, L"On" );
1195 static BOOL_ENTRY( SNAPTODEFBUTTON, FALSE, MOUSE_KEY, L"SnapToDefaultButton" );
1196 static BOOL_ENTRY_MIRROR( ICONTITLEWRAP, TRUE, DESKTOP_KEY, L"IconTitleWrap", METRICS_KEY );
1197 static BOOL_ENTRY( AUDIODESC_ON, FALSE, AUDIODESC_KEY, L"On" );
1199 static YESNO_ENTRY( BEEP, TRUE, SOUND_KEY, L"Beep" );
1201 static TWIPS_ENTRY( BORDER, -15, METRICS_KEY, L"BorderWidth" );
1202 static TWIPS_ENTRY( CAPTIONHEIGHT, -270, METRICS_KEY, L"CaptionHeight" );
1203 static TWIPS_ENTRY( CAPTIONWIDTH, -270, METRICS_KEY, L"CaptionWidth" );
1204 static TWIPS_ENTRY( ICONHORIZONTALSPACING, -1125, METRICS_KEY, L"IconSpacing" );
1205 static TWIPS_ENTRY( ICONVERTICALSPACING, -1125, METRICS_KEY, L"IconVerticalSpacing" );
1206 static TWIPS_ENTRY( MENUHEIGHT, -270, METRICS_KEY, L"MenuHeight" );
1207 static TWIPS_ENTRY( MENUWIDTH, -270, METRICS_KEY, L"MenuWidth" );
1208 static TWIPS_ENTRY( PADDEDBORDERWIDTH, 0, METRICS_KEY, L"PaddedBorderWidth" );
1209 static TWIPS_ENTRY( SCROLLHEIGHT, -240, METRICS_KEY, L"ScrollHeight" );
1210 static TWIPS_ENTRY( SCROLLWIDTH, -240, METRICS_KEY, L"ScrollWidth" );
1211 static TWIPS_ENTRY( SMCAPTIONHEIGHT, -225, METRICS_KEY, L"SmCaptionHeight" );
1212 static TWIPS_ENTRY( SMCAPTIONWIDTH, -225, METRICS_KEY, L"SmCaptionWidth" );
1214 static DWORD_ENTRY( ACTIVEWINDOWTRACKING, 0, MOUSE_KEY, L"ActiveWindowTracking" );
1215 static DWORD_ENTRY( ACTIVEWNDTRKTIMEOUT, 0, DESKTOP_KEY, L"ActiveWndTrackTimeout" );
1216 static DWORD_ENTRY( CARETWIDTH, 1, DESKTOP_KEY, L"CaretWidth" );
1217 static DWORD_ENTRY( DPISCALINGVER, 0, DESKTOP_KEY, L"DpiScalingVer" );
1218 static DWORD_ENTRY( FOCUSBORDERHEIGHT, 1, DESKTOP_KEY, L"FocusBorderHeight" );
1219 static DWORD_ENTRY( FOCUSBORDERWIDTH, 1, DESKTOP_KEY, L"FocusBorderWidth" );
1220 static DWORD_ENTRY( FONTSMOOTHINGCONTRAST, 0, DESKTOP_KEY, L"FontSmoothingGamma" );
1221 static DWORD_ENTRY( FONTSMOOTHINGORIENTATION, FE_FONTSMOOTHINGORIENTATIONRGB, DESKTOP_KEY, L"FontSmoothingOrientation" );
1222 static DWORD_ENTRY( FONTSMOOTHINGTYPE, FE_FONTSMOOTHINGSTANDARD, DESKTOP_KEY, L"FontSmoothingType" );
1223 static DWORD_ENTRY( FOREGROUNDFLASHCOUNT, 3, DESKTOP_KEY, L"ForegroundFlashCount" );
1224 static DWORD_ENTRY( FOREGROUNDLOCKTIMEOUT, 0, DESKTOP_KEY, L"ForegroundLockTimeout" );
1225 static DWORD_ENTRY( LOGPIXELS, 0, DESKTOP_KEY, L"LogPixels" );
1226 static DWORD_ENTRY( MOUSECLICKLOCKTIME, 1200, DESKTOP_KEY, L"ClickLockTime" );
1227 static DWORD_ENTRY( AUDIODESC_LOCALE, 0, AUDIODESC_KEY, L"Locale" );
1229 static PATH_ENTRY( DESKPATTERN, DESKTOP_KEY, L"Pattern" );
1230 static PATH_ENTRY( DESKWALLPAPER, DESKTOP_KEY, L"Wallpaper" );
1232 static BYTE user_prefs[8] = { 0x30, 0x00, 0x00, 0x80, 0x12, 0x00, 0x00, 0x00 };
1233 static BINARY_ENTRY( USERPREFERENCESMASK, user_prefs, DESKTOP_KEY, L"UserPreferencesMask" );
1235 static FONT_ENTRY( CAPTIONLOGFONT, FW_BOLD, METRICS_KEY, L"CaptionFont" );
1236 static FONT_ENTRY( ICONTITLELOGFONT, FW_NORMAL, METRICS_KEY, L"IconFont" );
1237 static FONT_ENTRY( MENULOGFONT, FW_NORMAL, METRICS_KEY, L"MenuFont" );
1238 static FONT_ENTRY( MESSAGELOGFONT, FW_NORMAL, METRICS_KEY, L"MessageFont" );
1239 static FONT_ENTRY( SMCAPTIONLOGFONT, FW_NORMAL, METRICS_KEY, L"SmCaptionFont" );
1240 static FONT_ENTRY( STATUSLOGFONT, FW_NORMAL, METRICS_KEY, L"StatusFont" );
1242 static USERPREF_ENTRY( MENUANIMATION, 0, 0x02 );
1243 static USERPREF_ENTRY( COMBOBOXANIMATION, 0, 0x04 );
1244 static USERPREF_ENTRY( LISTBOXSMOOTHSCROLLING, 0, 0x08 );
1245 static USERPREF_ENTRY( GRADIENTCAPTIONS, 0, 0x10 );
1246 static USERPREF_ENTRY( KEYBOARDCUES, 0, 0x20 );
1247 static USERPREF_ENTRY( ACTIVEWNDTRKZORDER, 0, 0x40 );
1248 static USERPREF_ENTRY( HOTTRACKING, 0, 0x80 );
1249 static USERPREF_ENTRY( MENUFADE, 1, 0x02 );
1250 static USERPREF_ENTRY( SELECTIONFADE, 1, 0x04 );
1251 static USERPREF_ENTRY( TOOLTIPANIMATION, 1, 0x08 );
1252 static USERPREF_ENTRY( TOOLTIPFADE, 1, 0x10 );
1253 static USERPREF_ENTRY( CURSORSHADOW, 1, 0x20 );
1254 static USERPREF_ENTRY( MOUSESONAR, 1, 0x40 );
1255 static USERPREF_ENTRY( MOUSECLICKLOCK, 1, 0x80 );
1256 static USERPREF_ENTRY( MOUSEVANISH, 2, 0x01 );
1257 static USERPREF_ENTRY( FLATMENU, 2, 0x02 );
1258 static USERPREF_ENTRY( DROPSHADOW, 2, 0x04 );
1259 static USERPREF_ENTRY( UIEFFECTS, 3, 0x80 );
1260 static USERPREF_ENTRY( DISABLEOVERLAPPEDCONTENT, 4, 0x01 );
1261 static USERPREF_ENTRY( CLIENTAREAANIMATION, 4, 0x02 );
1262 static USERPREF_ENTRY( CLEARTYPE, 4, 0x10 );
1263 static USERPREF_ENTRY( SPEECHRECOGNITION, 4, 0x20 );
1265 static struct sysparam_rgb_entry system_colors[] =
1267 #define RGB_ENTRY(name,val,reg) { { get_rgb_entry, set_rgb_entry, init_rgb_entry, COLORS_KEY, reg }, (val) }
1268 RGB_ENTRY( COLOR_SCROLLBAR, RGB(212, 208, 200), L"Scrollbar" ),
1269 RGB_ENTRY( COLOR_BACKGROUND, RGB(58, 110, 165), L"Background" ),
1270 RGB_ENTRY( COLOR_ACTIVECAPTION, RGB(10, 36, 106), L"ActiveTitle" ),
1271 RGB_ENTRY( COLOR_INACTIVECAPTION, RGB(128, 128, 128), L"InactiveTitle" ),
1272 RGB_ENTRY( COLOR_MENU, RGB(212, 208, 200), L"Menu" ),
1273 RGB_ENTRY( COLOR_WINDOW, RGB(255, 255, 255), L"Window" ),
1274 RGB_ENTRY( COLOR_WINDOWFRAME, RGB(0, 0, 0), L"WindowFrame" ),
1275 RGB_ENTRY( COLOR_MENUTEXT, RGB(0, 0, 0), L"MenuText" ),
1276 RGB_ENTRY( COLOR_WINDOWTEXT, RGB(0, 0, 0), L"WindowText" ),
1277 RGB_ENTRY( COLOR_CAPTIONTEXT, RGB(255, 255, 255), L"TitleText" ),
1278 RGB_ENTRY( COLOR_ACTIVEBORDER, RGB(212, 208, 200), L"ActiveBorder" ),
1279 RGB_ENTRY( COLOR_INACTIVEBORDER, RGB(212, 208, 200), L"InactiveBorder" ),
1280 RGB_ENTRY( COLOR_APPWORKSPACE, RGB(128, 128, 128), L"AppWorkSpace" ),
1281 RGB_ENTRY( COLOR_HIGHLIGHT, RGB(10, 36, 106), L"Hilight" ),
1282 RGB_ENTRY( COLOR_HIGHLIGHTTEXT, RGB(255, 255, 255), L"HilightText" ),
1283 RGB_ENTRY( COLOR_BTNFACE, RGB(212, 208, 200), L"ButtonFace" ),
1284 RGB_ENTRY( COLOR_BTNSHADOW, RGB(128, 128, 128), L"ButtonShadow" ),
1285 RGB_ENTRY( COLOR_GRAYTEXT, RGB(128, 128, 128), L"GrayText" ),
1286 RGB_ENTRY( COLOR_BTNTEXT, RGB(0, 0, 0), L"ButtonText" ),
1287 RGB_ENTRY( COLOR_INACTIVECAPTIONTEXT, RGB(212, 208, 200), L"InactiveTitleText" ),
1288 RGB_ENTRY( COLOR_BTNHIGHLIGHT, RGB(255, 255, 255), L"ButtonHilight" ),
1289 RGB_ENTRY( COLOR_3DDKSHADOW, RGB(64, 64, 64), L"ButtonDkShadow" ),
1290 RGB_ENTRY( COLOR_3DLIGHT, RGB(212, 208, 200), L"ButtonLight" ),
1291 RGB_ENTRY( COLOR_INFOTEXT, RGB(0, 0, 0), L"InfoText" ),
1292 RGB_ENTRY( COLOR_INFOBK, RGB(255, 255, 225), L"InfoWindow" ),
1293 RGB_ENTRY( COLOR_ALTERNATEBTNFACE, RGB(181, 181, 181), L"ButtonAlternateFace" ),
1294 RGB_ENTRY( COLOR_HOTLIGHT, RGB(0, 0, 200), L"HotTrackingColor" ),
1295 RGB_ENTRY( COLOR_GRADIENTACTIVECAPTION, RGB(166, 202, 240), L"GradientActiveTitle" ),
1296 RGB_ENTRY( COLOR_GRADIENTINACTIVECAPTION, RGB(192, 192, 192), L"GradientInactiveTitle" ),
1297 RGB_ENTRY( COLOR_MENUHILIGHT, RGB(10, 36, 106), L"MenuHilight" ),
1298 RGB_ENTRY( COLOR_MENUBAR, RGB(212, 208, 200), L"MenuBar" )
1299 #undef RGB_ENTRY
1302 /* entries that are initialized by default in the registry */
1303 static union sysparam_all_entry * const default_entries[] =
1305 (union sysparam_all_entry *)&entry_ACTIVEWINDOWTRACKING,
1306 (union sysparam_all_entry *)&entry_ACTIVEWNDTRKTIMEOUT,
1307 (union sysparam_all_entry *)&entry_BEEP,
1308 (union sysparam_all_entry *)&entry_BLOCKSENDINPUTRESETS,
1309 (union sysparam_all_entry *)&entry_BORDER,
1310 (union sysparam_all_entry *)&entry_CAPTIONHEIGHT,
1311 (union sysparam_all_entry *)&entry_CAPTIONWIDTH,
1312 (union sysparam_all_entry *)&entry_CARETWIDTH,
1313 (union sysparam_all_entry *)&entry_DESKWALLPAPER,
1314 (union sysparam_all_entry *)&entry_DOUBLECLICKTIME,
1315 (union sysparam_all_entry *)&entry_DOUBLECLKHEIGHT,
1316 (union sysparam_all_entry *)&entry_DOUBLECLKWIDTH,
1317 (union sysparam_all_entry *)&entry_DRAGFULLWINDOWS,
1318 (union sysparam_all_entry *)&entry_DRAGHEIGHT,
1319 (union sysparam_all_entry *)&entry_DRAGWIDTH,
1320 (union sysparam_all_entry *)&entry_FOCUSBORDERHEIGHT,
1321 (union sysparam_all_entry *)&entry_FOCUSBORDERWIDTH,
1322 (union sysparam_all_entry *)&entry_FONTSMOOTHING,
1323 (union sysparam_all_entry *)&entry_FONTSMOOTHINGCONTRAST,
1324 (union sysparam_all_entry *)&entry_FONTSMOOTHINGORIENTATION,
1325 (union sysparam_all_entry *)&entry_FONTSMOOTHINGTYPE,
1326 (union sysparam_all_entry *)&entry_FOREGROUNDFLASHCOUNT,
1327 (union sysparam_all_entry *)&entry_FOREGROUNDLOCKTIMEOUT,
1328 (union sysparam_all_entry *)&entry_ICONHORIZONTALSPACING,
1329 (union sysparam_all_entry *)&entry_ICONTITLEWRAP,
1330 (union sysparam_all_entry *)&entry_ICONVERTICALSPACING,
1331 (union sysparam_all_entry *)&entry_KEYBOARDDELAY,
1332 (union sysparam_all_entry *)&entry_KEYBOARDPREF,
1333 (union sysparam_all_entry *)&entry_KEYBOARDSPEED,
1334 (union sysparam_all_entry *)&entry_LOWPOWERACTIVE,
1335 (union sysparam_all_entry *)&entry_MENUHEIGHT,
1336 (union sysparam_all_entry *)&entry_MENUSHOWDELAY,
1337 (union sysparam_all_entry *)&entry_MENUWIDTH,
1338 (union sysparam_all_entry *)&entry_MOUSEACCELERATION,
1339 (union sysparam_all_entry *)&entry_MOUSEBUTTONSWAP,
1340 (union sysparam_all_entry *)&entry_MOUSECLICKLOCKTIME,
1341 (union sysparam_all_entry *)&entry_MOUSEHOVERHEIGHT,
1342 (union sysparam_all_entry *)&entry_MOUSEHOVERTIME,
1343 (union sysparam_all_entry *)&entry_MOUSEHOVERWIDTH,
1344 (union sysparam_all_entry *)&entry_MOUSESPEED,
1345 (union sysparam_all_entry *)&entry_MOUSETHRESHOLD1,
1346 (union sysparam_all_entry *)&entry_MOUSETHRESHOLD2,
1347 (union sysparam_all_entry *)&entry_PADDEDBORDERWIDTH,
1348 (union sysparam_all_entry *)&entry_SCREENREADER,
1349 (union sysparam_all_entry *)&entry_SCROLLHEIGHT,
1350 (union sysparam_all_entry *)&entry_SCROLLWIDTH,
1351 (union sysparam_all_entry *)&entry_SHOWSOUNDS,
1352 (union sysparam_all_entry *)&entry_SMCAPTIONHEIGHT,
1353 (union sysparam_all_entry *)&entry_SMCAPTIONWIDTH,
1354 (union sysparam_all_entry *)&entry_SNAPTODEFBUTTON,
1355 (union sysparam_all_entry *)&entry_USERPREFERENCESMASK,
1356 (union sysparam_all_entry *)&entry_WHEELSCROLLCHARS,
1357 (union sysparam_all_entry *)&entry_WHEELSCROLLLINES,
1358 (union sysparam_all_entry *)&entry_AUDIODESC_LOCALE,
1359 (union sysparam_all_entry *)&entry_AUDIODESC_ON,
1362 /***********************************************************************
1363 * SYSPARAMS_Init
1365 void SYSPARAMS_Init(void)
1367 HKEY key;
1368 DWORD i, dispos, dpi_scaling;
1370 /* this one must be non-volatile */
1371 if (RegCreateKeyW( HKEY_CURRENT_USER, L"Software\\Wine", &key ))
1373 ERR("Can't create wine registry branch\n");
1374 return;
1377 /* @@ Wine registry key: HKCU\Software\Wine\Temporary System Parameters */
1378 if (RegCreateKeyExW( key, L"Temporary System Parameters", 0, 0,
1379 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, 0, &volatile_base_key, &dispos ))
1380 ERR("Can't create non-permanent wine registry branch\n");
1382 RegCloseKey( key );
1384 get_dword_entry( (union sysparam_all_entry *)&entry_LOGPIXELS, 0, &system_dpi, 0 );
1385 if (!system_dpi) /* check fallback key */
1387 if (!RegOpenKeyW( HKEY_CURRENT_CONFIG, L"Software\\Fonts", &key ))
1389 DWORD type, size = sizeof(system_dpi);
1390 if (RegQueryValueExW( key, L"LogPixels", NULL, &type, (void *)&system_dpi, &size ) ||
1391 type != REG_DWORD)
1392 system_dpi = 0;
1393 RegCloseKey( key );
1396 if (!system_dpi) system_dpi = USER_DEFAULT_SCREEN_DPI;
1398 /* FIXME: what do the DpiScalingVer flags mean? */
1399 get_dword_entry( (union sysparam_all_entry *)&entry_DPISCALINGVER, 0, &dpi_scaling, 0 );
1400 if (!dpi_scaling)
1402 default_awareness = DPI_AWARENESS_PER_MONITOR_AWARE;
1403 dpi_awareness = 0x10 | default_awareness;
1406 if (volatile_base_key && dispos == REG_CREATED_NEW_KEY) /* first process, initialize entries */
1408 for (i = 0; i < ARRAY_SIZE( default_entries ); i++)
1409 default_entries[i]->hdr.init( default_entries[i] );
1413 static BOOL update_desktop_wallpaper(void)
1415 DWORD pid;
1417 if (GetWindowThreadProcessId( GetDesktopWindow(), &pid ) && pid == GetCurrentProcessId())
1419 WCHAR wallpaper[MAX_PATH], pattern[256];
1421 entry_DESKWALLPAPER.hdr.loaded = entry_DESKPATTERN.hdr.loaded = FALSE;
1422 if (get_entry( &entry_DESKWALLPAPER, MAX_PATH, wallpaper ) &&
1423 get_entry( &entry_DESKPATTERN, 256, pattern ))
1424 update_wallpaper( wallpaper, pattern );
1426 else SendMessageW( GetDesktopWindow(), WM_SETTINGCHANGE, SPI_SETDESKWALLPAPER, 0 );
1427 return TRUE;
1431 /***********************************************************************
1432 * SystemParametersInfoForDpi (USER32.@)
1434 BOOL WINAPI SystemParametersInfoForDpi( UINT action, UINT val, PVOID ptr, UINT winini, UINT dpi )
1436 BOOL ret = FALSE;
1438 switch (action)
1440 case SPI_GETICONTITLELOGFONT:
1441 ret = get_entry_dpi( &entry_ICONTITLELOGFONT, val, ptr, dpi );
1442 break;
1443 case SPI_GETNONCLIENTMETRICS:
1445 NONCLIENTMETRICSW *ncm = ptr;
1447 if (!ncm) break;
1448 ret = get_entry_dpi( &entry_BORDER, 0, &ncm->iBorderWidth, dpi ) &&
1449 get_entry_dpi( &entry_SCROLLWIDTH, 0, &ncm->iScrollWidth, dpi ) &&
1450 get_entry_dpi( &entry_SCROLLHEIGHT, 0, &ncm->iScrollHeight, dpi ) &&
1451 get_entry_dpi( &entry_CAPTIONWIDTH, 0, &ncm->iCaptionWidth, dpi ) &&
1452 get_entry_dpi( &entry_CAPTIONHEIGHT, 0, &ncm->iCaptionHeight, dpi ) &&
1453 get_entry_dpi( &entry_CAPTIONLOGFONT, 0, &ncm->lfCaptionFont, dpi ) &&
1454 get_entry_dpi( &entry_SMCAPTIONWIDTH, 0, &ncm->iSmCaptionWidth, dpi ) &&
1455 get_entry_dpi( &entry_SMCAPTIONHEIGHT, 0, &ncm->iSmCaptionHeight, dpi ) &&
1456 get_entry_dpi( &entry_SMCAPTIONLOGFONT, 0, &ncm->lfSmCaptionFont, dpi ) &&
1457 get_entry_dpi( &entry_MENUWIDTH, 0, &ncm->iMenuWidth, dpi ) &&
1458 get_entry_dpi( &entry_MENUHEIGHT, 0, &ncm->iMenuHeight, dpi ) &&
1459 get_entry_dpi( &entry_MENULOGFONT, 0, &ncm->lfMenuFont, dpi ) &&
1460 get_entry_dpi( &entry_STATUSLOGFONT, 0, &ncm->lfStatusFont, dpi ) &&
1461 get_entry_dpi( &entry_MESSAGELOGFONT, 0, &ncm->lfMessageFont, dpi );
1462 if (ret && ncm->cbSize == sizeof(NONCLIENTMETRICSW))
1463 ret = get_entry_dpi( &entry_PADDEDBORDERWIDTH, 0, &ncm->iPaddedBorderWidth, dpi );
1464 normalize_nonclientmetrics( ncm );
1465 break;
1467 case SPI_GETICONMETRICS:
1469 ICONMETRICSW *im = ptr;
1470 if (im && im->cbSize == sizeof(*im))
1471 ret = get_entry_dpi( &entry_ICONHORIZONTALSPACING, 0, &im->iHorzSpacing, dpi ) &&
1472 get_entry_dpi( &entry_ICONVERTICALSPACING, 0, &im->iVertSpacing, dpi ) &&
1473 get_entry_dpi( &entry_ICONTITLEWRAP, 0, &im->iTitleWrap, dpi ) &&
1474 get_entry_dpi( &entry_ICONTITLELOGFONT, 0, &im->lfFont, dpi );
1475 break;
1477 default:
1478 SetLastError( ERROR_INVALID_PARAMETER );
1479 break;
1481 return ret;
1485 /***********************************************************************
1486 * SystemParametersInfoW (USER32.@)
1488 * Each system parameter has flag which shows whether the parameter
1489 * is loaded or not. Parameters, stored directly in SysParametersInfo are
1490 * loaded from registry only when they are requested and the flag is
1491 * "false", after the loading the flag is set to "true". On interprocess
1492 * notification of the parameter change the corresponding parameter flag is
1493 * set to "false". The parameter value will be reloaded when it is requested
1494 * the next time.
1495 * Parameters, backed by or depend on GetSystemMetrics are processed
1496 * differently. These parameters are always loaded. They are reloaded right
1497 * away on interprocess change notification. We can't do lazy loading because
1498 * we don't want to complicate GetSystemMetrics.
1499 * Parameters, backed by X settings are read from corresponding setting.
1500 * On the parameter change request the setting is changed. Interprocess change
1501 * notifications are ignored.
1502 * When parameter value is updated the changed value is stored in permanent
1503 * registry branch if saving is requested. Otherwise it is stored
1504 * in temporary branch
1506 * Some SPI values can also be stored as Twips values in the registry,
1507 * don't forget the conversion!
1509 BOOL WINAPI SystemParametersInfoW( UINT uiAction, UINT uiParam,
1510 PVOID pvParam, UINT fWinIni )
1512 #define WINE_SPI_FIXME(x) \
1513 case x: \
1515 static BOOL warn = TRUE; \
1516 if (warn) \
1518 warn = FALSE; \
1519 FIXME( "Unimplemented action: %u (%s)\n", x, #x ); \
1522 SetLastError( ERROR_INVALID_SPI_VALUE ); \
1523 ret = FALSE; \
1524 break
1525 #define WINE_SPI_WARN(x) \
1526 case x: \
1527 WARN( "Ignored action: %u (%s)\n", x, #x ); \
1528 ret = TRUE; \
1529 break
1531 BOOL ret = USER_Driver->pSystemParametersInfo( uiAction, uiParam, pvParam, fWinIni );
1532 unsigned spi_idx = 0;
1534 if (!ret) switch (uiAction)
1536 case SPI_GETBEEP:
1537 ret = get_entry( &entry_BEEP, uiParam, pvParam );
1538 break;
1539 case SPI_SETBEEP:
1540 ret = set_entry( &entry_BEEP, uiParam, pvParam, fWinIni );
1541 break;
1542 case SPI_GETMOUSE:
1543 ret = get_entry( &entry_MOUSETHRESHOLD1, uiParam, (INT *)pvParam ) &&
1544 get_entry( &entry_MOUSETHRESHOLD2, uiParam, (INT *)pvParam + 1 ) &&
1545 get_entry( &entry_MOUSEACCELERATION, uiParam, (INT *)pvParam + 2 );
1546 break;
1547 case SPI_SETMOUSE:
1548 ret = set_entry( &entry_MOUSETHRESHOLD1, ((INT *)pvParam)[0], pvParam, fWinIni ) &&
1549 set_entry( &entry_MOUSETHRESHOLD2, ((INT *)pvParam)[1], pvParam, fWinIni ) &&
1550 set_entry( &entry_MOUSEACCELERATION, ((INT *)pvParam)[2], pvParam, fWinIni );
1551 break;
1552 case SPI_GETBORDER:
1553 ret = get_entry( &entry_BORDER, uiParam, pvParam );
1554 if (*(INT*)pvParam < 1) *(INT*)pvParam = 1;
1555 break;
1556 case SPI_SETBORDER:
1557 ret = set_entry( &entry_BORDER, uiParam, pvParam, fWinIni );
1558 break;
1559 case SPI_GETKEYBOARDSPEED:
1560 ret = get_entry( &entry_KEYBOARDSPEED, uiParam, pvParam );
1561 break;
1562 case SPI_SETKEYBOARDSPEED:
1563 if (uiParam > 31) uiParam = 31;
1564 ret = set_entry( &entry_KEYBOARDSPEED, uiParam, pvParam, fWinIni );
1565 break;
1567 /* not implemented in Windows */
1568 WINE_SPI_WARN(SPI_LANGDRIVER); /* 12 */
1570 case SPI_ICONHORIZONTALSPACING:
1571 if (pvParam != NULL)
1572 ret = get_entry( &entry_ICONHORIZONTALSPACING, uiParam, pvParam );
1573 else
1575 int min_val = map_to_dpi( 32, GetDpiForSystem() );
1576 ret = set_entry( &entry_ICONHORIZONTALSPACING, max( min_val, uiParam ), pvParam, fWinIni );
1578 break;
1579 case SPI_GETSCREENSAVETIMEOUT:
1580 ret = get_entry( &entry_SCREENSAVETIMEOUT, uiParam, pvParam );
1581 break;
1582 case SPI_SETSCREENSAVETIMEOUT:
1583 ret = set_entry( &entry_SCREENSAVETIMEOUT, uiParam, pvParam, fWinIni );
1584 break;
1585 case SPI_GETSCREENSAVEACTIVE:
1586 ret = get_entry( &entry_SCREENSAVEACTIVE, uiParam, pvParam );
1587 break;
1588 case SPI_SETSCREENSAVEACTIVE:
1589 ret = set_entry( &entry_SCREENSAVEACTIVE, uiParam, pvParam, fWinIni );
1590 break;
1591 case SPI_GETGRIDGRANULARITY:
1592 ret = get_entry( &entry_GRIDGRANULARITY, uiParam, pvParam );
1593 break;
1594 case SPI_SETGRIDGRANULARITY:
1595 ret = set_entry( &entry_GRIDGRANULARITY, uiParam, pvParam, fWinIni );
1596 break;
1597 case SPI_SETDESKWALLPAPER:
1598 if (!pvParam || set_entry( &entry_DESKWALLPAPER, uiParam, pvParam, fWinIni ))
1599 ret = update_desktop_wallpaper();
1600 break;
1601 case SPI_SETDESKPATTERN:
1602 if (!pvParam || set_entry( &entry_DESKPATTERN, uiParam, pvParam, fWinIni ))
1603 ret = update_desktop_wallpaper();
1604 break;
1605 case SPI_GETKEYBOARDDELAY:
1606 ret = get_entry( &entry_KEYBOARDDELAY, uiParam, pvParam );
1607 break;
1608 case SPI_SETKEYBOARDDELAY:
1609 ret = set_entry( &entry_KEYBOARDDELAY, uiParam, pvParam, fWinIni );
1610 break;
1611 case SPI_ICONVERTICALSPACING:
1612 if (pvParam != NULL)
1613 ret = get_entry( &entry_ICONVERTICALSPACING, uiParam, pvParam );
1614 else
1616 int min_val = map_to_dpi( 32, GetDpiForSystem() );
1617 ret = set_entry( &entry_ICONVERTICALSPACING, max( min_val, uiParam ), pvParam, fWinIni );
1619 break;
1620 case SPI_GETICONTITLEWRAP:
1621 ret = get_entry( &entry_ICONTITLEWRAP, uiParam, pvParam );
1622 break;
1623 case SPI_SETICONTITLEWRAP:
1624 ret = set_entry( &entry_ICONTITLEWRAP, uiParam, pvParam, fWinIni );
1625 break;
1626 case SPI_GETMENUDROPALIGNMENT:
1627 ret = get_entry( &entry_MENUDROPALIGNMENT, uiParam, pvParam );
1628 break;
1629 case SPI_SETMENUDROPALIGNMENT:
1630 ret = set_entry( &entry_MENUDROPALIGNMENT, uiParam, pvParam, fWinIni );
1631 break;
1632 case SPI_SETDOUBLECLKWIDTH:
1633 ret = set_entry( &entry_DOUBLECLKWIDTH, uiParam, pvParam, fWinIni );
1634 break;
1635 case SPI_SETDOUBLECLKHEIGHT:
1636 ret = set_entry( &entry_DOUBLECLKHEIGHT, uiParam, pvParam, fWinIni );
1637 break;
1638 case SPI_GETICONTITLELOGFONT:
1639 ret = get_entry( &entry_ICONTITLELOGFONT, uiParam, pvParam );
1640 break;
1641 case SPI_SETDOUBLECLICKTIME:
1642 ret = set_entry( &entry_DOUBLECLICKTIME, uiParam, pvParam, fWinIni );
1643 break;
1644 case SPI_SETMOUSEBUTTONSWAP:
1645 ret = set_entry( &entry_MOUSEBUTTONSWAP, uiParam, pvParam, fWinIni );
1646 break;
1647 case SPI_SETICONTITLELOGFONT:
1648 ret = set_entry( &entry_ICONTITLELOGFONT, uiParam, pvParam, fWinIni );
1649 break;
1651 case SPI_GETFASTTASKSWITCH: /* 35 */
1652 if (!pvParam) return FALSE;
1653 *(BOOL *)pvParam = TRUE;
1654 ret = TRUE;
1655 break;
1657 case SPI_SETFASTTASKSWITCH: /* 36 */
1658 /* the action is disabled */
1659 ret = FALSE;
1660 break;
1662 case SPI_SETDRAGFULLWINDOWS:
1663 ret = set_entry( &entry_DRAGFULLWINDOWS, uiParam, pvParam, fWinIni );
1664 break;
1665 case SPI_GETDRAGFULLWINDOWS:
1666 ret = get_entry( &entry_DRAGFULLWINDOWS, uiParam, pvParam );
1667 break;
1668 case SPI_GETNONCLIENTMETRICS:
1670 LPNONCLIENTMETRICSW lpnm = pvParam;
1671 int padded_border;
1673 if (!pvParam) return FALSE;
1675 ret = get_entry( &entry_BORDER, 0, &lpnm->iBorderWidth ) &&
1676 get_entry( &entry_PADDEDBORDERWIDTH, 0, &padded_border ) &&
1677 get_entry( &entry_SCROLLWIDTH, 0, &lpnm->iScrollWidth ) &&
1678 get_entry( &entry_SCROLLHEIGHT, 0, &lpnm->iScrollHeight ) &&
1679 get_entry( &entry_CAPTIONWIDTH, 0, &lpnm->iCaptionWidth ) &&
1680 get_entry( &entry_CAPTIONHEIGHT, 0, &lpnm->iCaptionHeight ) &&
1681 get_entry( &entry_CAPTIONLOGFONT, 0, &lpnm->lfCaptionFont ) &&
1682 get_entry( &entry_SMCAPTIONWIDTH, 0, &lpnm->iSmCaptionWidth ) &&
1683 get_entry( &entry_SMCAPTIONHEIGHT, 0, &lpnm->iSmCaptionHeight ) &&
1684 get_entry( &entry_SMCAPTIONLOGFONT, 0, &lpnm->lfSmCaptionFont ) &&
1685 get_entry( &entry_MENUWIDTH, 0, &lpnm->iMenuWidth ) &&
1686 get_entry( &entry_MENUHEIGHT, 0, &lpnm->iMenuHeight ) &&
1687 get_entry( &entry_MENULOGFONT, 0, &lpnm->lfMenuFont ) &&
1688 get_entry( &entry_STATUSLOGFONT, 0, &lpnm->lfStatusFont ) &&
1689 get_entry( &entry_MESSAGELOGFONT, 0, &lpnm->lfMessageFont );
1690 if (ret)
1692 lpnm->iBorderWidth += padded_border;
1693 if (lpnm->cbSize == sizeof(NONCLIENTMETRICSW)) lpnm->iPaddedBorderWidth = 0;
1695 normalize_nonclientmetrics( lpnm );
1696 break;
1698 case SPI_SETNONCLIENTMETRICS:
1700 LPNONCLIENTMETRICSW lpnm = pvParam;
1701 int padded_border;
1703 if (lpnm && (lpnm->cbSize == sizeof(NONCLIENTMETRICSW) ||
1704 lpnm->cbSize == FIELD_OFFSET(NONCLIENTMETRICSW, iPaddedBorderWidth)))
1706 get_entry( &entry_PADDEDBORDERWIDTH, 0, &padded_border );
1708 ret = set_entry( &entry_BORDER, lpnm->iBorderWidth - padded_border, NULL, fWinIni ) &&
1709 set_entry( &entry_SCROLLWIDTH, lpnm->iScrollWidth, NULL, fWinIni ) &&
1710 set_entry( &entry_SCROLLHEIGHT, lpnm->iScrollHeight, NULL, fWinIni ) &&
1711 set_entry( &entry_CAPTIONWIDTH, lpnm->iCaptionWidth, NULL, fWinIni ) &&
1712 set_entry( &entry_CAPTIONHEIGHT, lpnm->iCaptionHeight, NULL, fWinIni ) &&
1713 set_entry( &entry_SMCAPTIONWIDTH, lpnm->iSmCaptionWidth, NULL, fWinIni ) &&
1714 set_entry( &entry_SMCAPTIONHEIGHT, lpnm->iSmCaptionHeight, NULL, fWinIni ) &&
1715 set_entry( &entry_MENUWIDTH, lpnm->iMenuWidth, NULL, fWinIni ) &&
1716 set_entry( &entry_MENUHEIGHT, lpnm->iMenuHeight, NULL, fWinIni ) &&
1717 set_entry( &entry_MENULOGFONT, 0, &lpnm->lfMenuFont, fWinIni ) &&
1718 set_entry( &entry_CAPTIONLOGFONT, 0, &lpnm->lfCaptionFont, fWinIni ) &&
1719 set_entry( &entry_SMCAPTIONLOGFONT, 0, &lpnm->lfSmCaptionFont, fWinIni ) &&
1720 set_entry( &entry_STATUSLOGFONT, 0, &lpnm->lfStatusFont, fWinIni ) &&
1721 set_entry( &entry_MESSAGELOGFONT, 0, &lpnm->lfMessageFont, fWinIni );
1723 break;
1725 case SPI_GETMINIMIZEDMETRICS:
1727 MINIMIZEDMETRICS * lpMm = pvParam;
1728 if (lpMm && lpMm->cbSize == sizeof(*lpMm)) {
1729 ret = get_entry( &entry_MINWIDTH, 0, &lpMm->iWidth ) &&
1730 get_entry( &entry_MINHORZGAP, 0, &lpMm->iHorzGap ) &&
1731 get_entry( &entry_MINVERTGAP, 0, &lpMm->iVertGap ) &&
1732 get_entry( &entry_MINARRANGE, 0, &lpMm->iArrange );
1733 lpMm->iWidth = max( 0, lpMm->iWidth );
1734 lpMm->iHorzGap = max( 0, lpMm->iHorzGap );
1735 lpMm->iVertGap = max( 0, lpMm->iVertGap );
1736 lpMm->iArrange &= 0x0f;
1738 break;
1740 case SPI_SETMINIMIZEDMETRICS:
1742 MINIMIZEDMETRICS * lpMm = pvParam;
1743 if (lpMm && lpMm->cbSize == sizeof(*lpMm))
1744 ret = set_entry( &entry_MINWIDTH, max( 0, lpMm->iWidth ), NULL, fWinIni ) &&
1745 set_entry( &entry_MINHORZGAP, max( 0, lpMm->iHorzGap ), NULL, fWinIni ) &&
1746 set_entry( &entry_MINVERTGAP, max( 0, lpMm->iVertGap ), NULL, fWinIni ) &&
1747 set_entry( &entry_MINARRANGE, lpMm->iArrange & 0x0f, NULL, fWinIni );
1748 break;
1750 case SPI_GETICONMETRICS:
1752 LPICONMETRICSW lpIcon = pvParam;
1753 if(lpIcon && lpIcon->cbSize == sizeof(*lpIcon))
1755 ret = get_entry( &entry_ICONHORIZONTALSPACING, 0, &lpIcon->iHorzSpacing ) &&
1756 get_entry( &entry_ICONVERTICALSPACING, 0, &lpIcon->iVertSpacing ) &&
1757 get_entry( &entry_ICONTITLEWRAP, 0, &lpIcon->iTitleWrap ) &&
1758 get_entry( &entry_ICONTITLELOGFONT, 0, &lpIcon->lfFont );
1760 break;
1762 case SPI_SETICONMETRICS:
1764 LPICONMETRICSW lpIcon = pvParam;
1765 if (lpIcon && lpIcon->cbSize == sizeof(*lpIcon))
1766 ret = set_entry( &entry_ICONVERTICALSPACING, max(32,lpIcon->iVertSpacing), NULL, fWinIni ) &&
1767 set_entry( &entry_ICONHORIZONTALSPACING, max(32,lpIcon->iHorzSpacing), NULL, fWinIni ) &&
1768 set_entry( &entry_ICONTITLEWRAP, lpIcon->iTitleWrap, NULL, fWinIni ) &&
1769 set_entry( &entry_ICONTITLELOGFONT, 0, &lpIcon->lfFont, fWinIni );
1770 break;
1773 case SPI_SETWORKAREA: /* 47 WINVER >= 0x400 */
1775 if (!pvParam) return FALSE;
1777 spi_idx = SPI_SETWORKAREA_IDX;
1778 work_area = *(RECT*)pvParam;
1779 spi_loaded[spi_idx] = TRUE;
1780 ret = TRUE;
1781 break;
1784 case SPI_GETWORKAREA: /* 48 WINVER >= 0x400 */
1786 if (!pvParam) return FALSE;
1788 spi_idx = SPI_SETWORKAREA_IDX;
1789 if (!spi_loaded[spi_idx])
1791 SetRect( &work_area, 0, 0,
1792 GetSystemMetrics( SM_CXSCREEN ),
1793 GetSystemMetrics( SM_CYSCREEN ) );
1794 EnumDisplayMonitors( 0, NULL, enum_monitors, (LPARAM)&work_area );
1795 spi_loaded[spi_idx] = TRUE;
1797 *(RECT*)pvParam = work_area;
1798 ret = TRUE;
1799 TRACE("work area %s\n", wine_dbgstr_rect( &work_area ));
1800 break;
1803 WINE_SPI_FIXME(SPI_SETPENWINDOWS); /* 49 WINVER >= 0x400 */
1805 case SPI_GETFILTERKEYS: /* 50 */
1807 LPFILTERKEYS lpFilterKeys = pvParam;
1808 WARN("SPI_GETFILTERKEYS not fully implemented\n");
1809 if (lpFilterKeys && lpFilterKeys->cbSize == sizeof(FILTERKEYS))
1811 /* Indicate that no FilterKeys feature available */
1812 lpFilterKeys->dwFlags = 0;
1813 lpFilterKeys->iWaitMSec = 0;
1814 lpFilterKeys->iDelayMSec = 0;
1815 lpFilterKeys->iRepeatMSec = 0;
1816 lpFilterKeys->iBounceMSec = 0;
1817 ret = TRUE;
1819 break;
1821 WINE_SPI_FIXME(SPI_SETFILTERKEYS); /* 51 */
1823 case SPI_GETTOGGLEKEYS: /* 52 */
1825 LPTOGGLEKEYS lpToggleKeys = pvParam;
1826 WARN("SPI_GETTOGGLEKEYS not fully implemented\n");
1827 if (lpToggleKeys && lpToggleKeys->cbSize == sizeof(TOGGLEKEYS))
1829 /* Indicate that no ToggleKeys feature available */
1830 lpToggleKeys->dwFlags = 0;
1831 ret = TRUE;
1833 break;
1835 WINE_SPI_FIXME(SPI_SETTOGGLEKEYS); /* 53 */
1837 case SPI_GETMOUSEKEYS: /* 54 */
1839 LPMOUSEKEYS lpMouseKeys = pvParam;
1840 WARN("SPI_GETMOUSEKEYS not fully implemented\n");
1841 if (lpMouseKeys && lpMouseKeys->cbSize == sizeof(MOUSEKEYS))
1843 /* Indicate that no MouseKeys feature available */
1844 lpMouseKeys->dwFlags = 0;
1845 lpMouseKeys->iMaxSpeed = 360;
1846 lpMouseKeys->iTimeToMaxSpeed = 1000;
1847 lpMouseKeys->iCtrlSpeed = 0;
1848 lpMouseKeys->dwReserved1 = 0;
1849 lpMouseKeys->dwReserved2 = 0;
1850 ret = TRUE;
1852 break;
1854 WINE_SPI_FIXME(SPI_SETMOUSEKEYS); /* 55 */
1856 case SPI_GETSHOWSOUNDS:
1857 ret = get_entry( &entry_SHOWSOUNDS, uiParam, pvParam );
1858 break;
1859 case SPI_SETSHOWSOUNDS:
1860 ret = set_entry( &entry_SHOWSOUNDS, uiParam, pvParam, fWinIni );
1861 break;
1863 case SPI_GETSTICKYKEYS: /* 58 */
1865 LPSTICKYKEYS lpStickyKeys = pvParam;
1866 WARN("SPI_GETSTICKYKEYS not fully implemented\n");
1867 if (lpStickyKeys && lpStickyKeys->cbSize == sizeof(STICKYKEYS))
1869 /* Indicate that no StickyKeys feature available */
1870 lpStickyKeys->dwFlags = 0;
1871 ret = TRUE;
1873 break;
1875 WINE_SPI_FIXME(SPI_SETSTICKYKEYS); /* 59 */
1877 case SPI_GETACCESSTIMEOUT: /* 60 */
1879 LPACCESSTIMEOUT lpAccessTimeout = pvParam;
1880 WARN("SPI_GETACCESSTIMEOUT not fully implemented\n");
1881 if (lpAccessTimeout && lpAccessTimeout->cbSize == sizeof(ACCESSTIMEOUT))
1883 /* Indicate that no accessibility features timeout is available */
1884 lpAccessTimeout->dwFlags = 0;
1885 lpAccessTimeout->iTimeOutMSec = 0;
1886 ret = TRUE;
1888 break;
1890 WINE_SPI_FIXME(SPI_SETACCESSTIMEOUT); /* 61 */
1892 case SPI_GETSERIALKEYS: /* 62 WINVER >= 0x400 */
1894 LPSERIALKEYSW lpSerialKeysW = pvParam;
1895 WARN("SPI_GETSERIALKEYS not fully implemented\n");
1896 if (lpSerialKeysW && lpSerialKeysW->cbSize == sizeof(SERIALKEYSW))
1898 /* Indicate that no SerialKeys feature available */
1899 lpSerialKeysW->dwFlags = 0;
1900 lpSerialKeysW->lpszActivePort = NULL;
1901 lpSerialKeysW->lpszPort = NULL;
1902 lpSerialKeysW->iBaudRate = 0;
1903 lpSerialKeysW->iPortState = 0;
1904 ret = TRUE;
1906 break;
1908 WINE_SPI_FIXME(SPI_SETSERIALKEYS); /* 63 WINVER >= 0x400 */
1910 case SPI_GETSOUNDSENTRY: /* 64 */
1912 LPSOUNDSENTRYW lpSoundSentryW = pvParam;
1913 WARN("SPI_GETSOUNDSENTRY not fully implemented\n");
1914 if (lpSoundSentryW && lpSoundSentryW->cbSize == sizeof(SOUNDSENTRYW))
1916 /* Indicate that no SoundSentry feature available */
1917 lpSoundSentryW->dwFlags = 0;
1918 lpSoundSentryW->iFSTextEffect = 0;
1919 lpSoundSentryW->iFSTextEffectMSec = 0;
1920 lpSoundSentryW->iFSTextEffectColorBits = 0;
1921 lpSoundSentryW->iFSGrafEffect = 0;
1922 lpSoundSentryW->iFSGrafEffectMSec = 0;
1923 lpSoundSentryW->iFSGrafEffectColor = 0;
1924 lpSoundSentryW->iWindowsEffect = 0;
1925 lpSoundSentryW->iWindowsEffectMSec = 0;
1926 lpSoundSentryW->lpszWindowsEffectDLL = 0;
1927 lpSoundSentryW->iWindowsEffectOrdinal = 0;
1928 ret = TRUE;
1930 break;
1932 WINE_SPI_FIXME(SPI_SETSOUNDSENTRY); /* 65 */
1934 case SPI_GETHIGHCONTRAST: /* 66 WINVER >= 0x400 */
1936 LPHIGHCONTRASTW lpHighContrastW = pvParam;
1937 WARN("SPI_GETHIGHCONTRAST not fully implemented\n");
1938 if (lpHighContrastW && lpHighContrastW->cbSize == sizeof(HIGHCONTRASTW))
1940 /* Indicate that no high contrast feature available */
1941 lpHighContrastW->dwFlags = 0;
1942 lpHighContrastW->lpszDefaultScheme = NULL;
1943 ret = TRUE;
1945 break;
1947 WINE_SPI_FIXME(SPI_SETHIGHCONTRAST); /* 67 WINVER >= 0x400 */
1949 case SPI_GETKEYBOARDPREF:
1950 ret = get_entry( &entry_KEYBOARDPREF, uiParam, pvParam );
1951 break;
1952 case SPI_SETKEYBOARDPREF:
1953 ret = set_entry( &entry_KEYBOARDPREF, uiParam, pvParam, fWinIni );
1954 break;
1955 case SPI_GETSCREENREADER:
1956 ret = get_entry( &entry_SCREENREADER, uiParam, pvParam );
1957 break;
1958 case SPI_SETSCREENREADER:
1959 ret = set_entry( &entry_SCREENREADER, uiParam, pvParam, fWinIni );
1960 break;
1962 case SPI_GETANIMATION: /* 72 WINVER >= 0x400 */
1964 LPANIMATIONINFO lpAnimInfo = pvParam;
1966 /* Tell it "disabled" */
1967 if (lpAnimInfo && lpAnimInfo->cbSize == sizeof(ANIMATIONINFO))
1969 lpAnimInfo->iMinAnimate = 0; /* Minimize and restore animation is disabled (nonzero == enabled) */
1970 ret = TRUE;
1972 break;
1974 WINE_SPI_WARN(SPI_SETANIMATION); /* 73 WINVER >= 0x400 */
1976 case SPI_GETFONTSMOOTHING:
1977 ret = get_entry( &entry_FONTSMOOTHING, uiParam, pvParam );
1978 if (ret) *(UINT *)pvParam = (*(UINT *)pvParam != 0);
1979 break;
1980 case SPI_SETFONTSMOOTHING:
1981 uiParam = uiParam ? 2 : 0; /* Win NT4/2k/XP behavior */
1982 ret = set_entry( &entry_FONTSMOOTHING, uiParam, pvParam, fWinIni );
1983 break;
1984 case SPI_SETDRAGWIDTH:
1985 ret = set_entry( &entry_DRAGWIDTH, uiParam, pvParam, fWinIni );
1986 break;
1987 case SPI_SETDRAGHEIGHT:
1988 ret = set_entry( &entry_DRAGHEIGHT, uiParam, pvParam, fWinIni );
1989 break;
1991 WINE_SPI_FIXME(SPI_SETHANDHELD); /* 78 WINVER >= 0x400 */
1993 WINE_SPI_FIXME(SPI_GETLOWPOWERTIMEOUT); /* 79 WINVER >= 0x400 */
1994 WINE_SPI_FIXME(SPI_GETPOWEROFFTIMEOUT); /* 80 WINVER >= 0x400 */
1995 WINE_SPI_FIXME(SPI_SETLOWPOWERTIMEOUT); /* 81 WINVER >= 0x400 */
1996 WINE_SPI_FIXME(SPI_SETPOWEROFFTIMEOUT); /* 82 WINVER >= 0x400 */
1998 case SPI_GETLOWPOWERACTIVE:
1999 ret = get_entry( &entry_LOWPOWERACTIVE, uiParam, pvParam );
2000 break;
2001 case SPI_SETLOWPOWERACTIVE:
2002 ret = set_entry( &entry_LOWPOWERACTIVE, uiParam, pvParam, fWinIni );
2003 break;
2004 case SPI_GETPOWEROFFACTIVE:
2005 ret = get_entry( &entry_POWEROFFACTIVE, uiParam, pvParam );
2006 break;
2007 case SPI_SETPOWEROFFACTIVE:
2008 ret = set_entry( &entry_POWEROFFACTIVE, uiParam, pvParam, fWinIni );
2009 break;
2011 WINE_SPI_FIXME(SPI_SETCURSORS); /* 87 WINVER >= 0x400 */
2012 WINE_SPI_FIXME(SPI_SETICONS); /* 88 WINVER >= 0x400 */
2014 case SPI_GETDEFAULTINPUTLANG: /* 89 WINVER >= 0x400 */
2015 ret = GetKeyboardLayout(0) != 0;
2016 break;
2018 WINE_SPI_FIXME(SPI_SETDEFAULTINPUTLANG); /* 90 WINVER >= 0x400 */
2020 WINE_SPI_FIXME(SPI_SETLANGTOGGLE); /* 91 WINVER >= 0x400 */
2022 case SPI_GETWINDOWSEXTENSION: /* 92 WINVER >= 0x400 */
2023 WARN("pretend no support for Win9x Plus! for now.\n");
2024 ret = FALSE; /* yes, this is the result value */
2025 break;
2026 case SPI_SETMOUSETRAILS:
2027 ret = set_entry( &entry_MOUSETRAILS, uiParam, pvParam, fWinIni );
2028 break;
2029 case SPI_GETMOUSETRAILS:
2030 ret = get_entry( &entry_MOUSETRAILS, uiParam, pvParam );
2031 break;
2032 case SPI_GETSNAPTODEFBUTTON:
2033 ret = get_entry( &entry_SNAPTODEFBUTTON, uiParam, pvParam );
2034 break;
2035 case SPI_SETSNAPTODEFBUTTON:
2036 ret = set_entry( &entry_SNAPTODEFBUTTON, uiParam, pvParam, fWinIni );
2037 break;
2038 case SPI_SETSCREENSAVERRUNNING:
2039 ret = set_entry( &entry_SCREENSAVERRUNNING, uiParam, pvParam, fWinIni );
2040 break;
2041 case SPI_GETMOUSEHOVERWIDTH:
2042 ret = get_entry( &entry_MOUSEHOVERWIDTH, uiParam, pvParam );
2043 break;
2044 case SPI_SETMOUSEHOVERWIDTH:
2045 ret = set_entry( &entry_MOUSEHOVERWIDTH, uiParam, pvParam, fWinIni );
2046 break;
2047 case SPI_GETMOUSEHOVERHEIGHT:
2048 ret = get_entry( &entry_MOUSEHOVERHEIGHT, uiParam, pvParam );
2049 break;
2050 case SPI_SETMOUSEHOVERHEIGHT:
2051 ret = set_entry( &entry_MOUSEHOVERHEIGHT, uiParam, pvParam, fWinIni );
2052 break;
2053 case SPI_GETMOUSEHOVERTIME:
2054 ret = get_entry( &entry_MOUSEHOVERTIME, uiParam, pvParam );
2055 break;
2056 case SPI_SETMOUSEHOVERTIME:
2057 ret = set_entry( &entry_MOUSEHOVERTIME, uiParam, pvParam, fWinIni );
2058 break;
2059 case SPI_GETWHEELSCROLLLINES:
2060 ret = get_entry( &entry_WHEELSCROLLLINES, uiParam, pvParam );
2061 break;
2062 case SPI_SETWHEELSCROLLLINES:
2063 ret = set_entry( &entry_WHEELSCROLLLINES, uiParam, pvParam, fWinIni );
2064 break;
2065 case SPI_GETMENUSHOWDELAY:
2066 ret = get_entry( &entry_MENUSHOWDELAY, uiParam, pvParam );
2067 break;
2068 case SPI_SETMENUSHOWDELAY:
2069 ret = set_entry( &entry_MENUSHOWDELAY, uiParam, pvParam, fWinIni );
2070 break;
2071 case SPI_GETWHEELSCROLLCHARS:
2072 ret = get_entry( &entry_WHEELSCROLLCHARS, uiParam, pvParam );
2073 break;
2074 case SPI_SETWHEELSCROLLCHARS:
2075 ret = set_entry( &entry_WHEELSCROLLCHARS, uiParam, pvParam, fWinIni );
2076 break;
2078 WINE_SPI_FIXME(SPI_GETSHOWIMEUI); /* 110 _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
2079 WINE_SPI_FIXME(SPI_SETSHOWIMEUI); /* 111 _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
2081 case SPI_GETMOUSESPEED:
2082 ret = get_entry( &entry_MOUSESPEED, uiParam, pvParam );
2083 break;
2084 case SPI_SETMOUSESPEED:
2085 ret = set_entry( &entry_MOUSESPEED, uiParam, pvParam, fWinIni );
2086 break;
2087 case SPI_GETSCREENSAVERRUNNING:
2088 ret = get_entry( &entry_SCREENSAVERRUNNING, uiParam, pvParam );
2089 break;
2090 case SPI_GETDESKWALLPAPER:
2091 ret = get_entry( &entry_DESKWALLPAPER, uiParam, pvParam );
2092 break;
2093 case SPI_GETACTIVEWINDOWTRACKING:
2094 ret = get_entry( &entry_ACTIVEWINDOWTRACKING, uiParam, pvParam );
2095 break;
2096 case SPI_SETACTIVEWINDOWTRACKING:
2097 ret = set_entry( &entry_ACTIVEWINDOWTRACKING, uiParam, pvParam, fWinIni );
2098 break;
2099 case SPI_GETMENUANIMATION:
2100 ret = get_entry( &entry_MENUANIMATION, uiParam, pvParam );
2101 break;
2102 case SPI_SETMENUANIMATION:
2103 ret = set_entry( &entry_MENUANIMATION, uiParam, pvParam, fWinIni );
2104 break;
2105 case SPI_GETCOMBOBOXANIMATION:
2106 ret = get_entry( &entry_COMBOBOXANIMATION, uiParam, pvParam );
2107 break;
2108 case SPI_SETCOMBOBOXANIMATION:
2109 ret = set_entry( &entry_COMBOBOXANIMATION, uiParam, pvParam, fWinIni );
2110 break;
2111 case SPI_GETLISTBOXSMOOTHSCROLLING:
2112 ret = get_entry( &entry_LISTBOXSMOOTHSCROLLING, uiParam, pvParam );
2113 break;
2114 case SPI_SETLISTBOXSMOOTHSCROLLING:
2115 ret = set_entry( &entry_LISTBOXSMOOTHSCROLLING, uiParam, pvParam, fWinIni );
2116 break;
2117 case SPI_GETGRADIENTCAPTIONS:
2118 ret = get_entry( &entry_GRADIENTCAPTIONS, uiParam, pvParam );
2119 break;
2120 case SPI_SETGRADIENTCAPTIONS:
2121 ret = set_entry( &entry_GRADIENTCAPTIONS, uiParam, pvParam, fWinIni );
2122 break;
2123 case SPI_GETKEYBOARDCUES:
2124 ret = get_entry( &entry_KEYBOARDCUES, uiParam, pvParam );
2125 break;
2126 case SPI_SETKEYBOARDCUES:
2127 ret = set_entry( &entry_KEYBOARDCUES, uiParam, pvParam, fWinIni );
2128 break;
2129 case SPI_GETACTIVEWNDTRKZORDER:
2130 ret = get_entry( &entry_ACTIVEWNDTRKZORDER, uiParam, pvParam );
2131 break;
2132 case SPI_SETACTIVEWNDTRKZORDER:
2133 ret = set_entry( &entry_ACTIVEWNDTRKZORDER, uiParam, pvParam, fWinIni );
2134 break;
2135 case SPI_GETHOTTRACKING:
2136 ret = get_entry( &entry_HOTTRACKING, uiParam, pvParam );
2137 break;
2138 case SPI_SETHOTTRACKING:
2139 ret = set_entry( &entry_HOTTRACKING, uiParam, pvParam, fWinIni );
2140 break;
2141 case SPI_GETMENUFADE:
2142 ret = get_entry( &entry_MENUFADE, uiParam, pvParam );
2143 break;
2144 case SPI_SETMENUFADE:
2145 ret = set_entry( &entry_MENUFADE, uiParam, pvParam, fWinIni );
2146 break;
2147 case SPI_GETSELECTIONFADE:
2148 ret = get_entry( &entry_SELECTIONFADE, uiParam, pvParam );
2149 break;
2150 case SPI_SETSELECTIONFADE:
2151 ret = set_entry( &entry_SELECTIONFADE, uiParam, pvParam, fWinIni );
2152 break;
2153 case SPI_GETTOOLTIPANIMATION:
2154 ret = get_entry( &entry_TOOLTIPANIMATION, uiParam, pvParam );
2155 break;
2156 case SPI_SETTOOLTIPANIMATION:
2157 ret = set_entry( &entry_TOOLTIPANIMATION, uiParam, pvParam, fWinIni );
2158 break;
2159 case SPI_GETTOOLTIPFADE:
2160 ret = get_entry( &entry_TOOLTIPFADE, uiParam, pvParam );
2161 break;
2162 case SPI_SETTOOLTIPFADE:
2163 ret = set_entry( &entry_TOOLTIPFADE, uiParam, pvParam, fWinIni );
2164 break;
2165 case SPI_GETCURSORSHADOW:
2166 ret = get_entry( &entry_CURSORSHADOW, uiParam, pvParam );
2167 break;
2168 case SPI_SETCURSORSHADOW:
2169 ret = set_entry( &entry_CURSORSHADOW, uiParam, pvParam, fWinIni );
2170 break;
2171 case SPI_GETMOUSESONAR:
2172 ret = get_entry( &entry_MOUSESONAR, uiParam, pvParam );
2173 break;
2174 case SPI_SETMOUSESONAR:
2175 ret = set_entry( &entry_MOUSESONAR, uiParam, pvParam, fWinIni );
2176 break;
2177 case SPI_GETMOUSECLICKLOCK:
2178 ret = get_entry( &entry_MOUSECLICKLOCK, uiParam, pvParam );
2179 break;
2180 case SPI_SETMOUSECLICKLOCK:
2181 ret = set_entry( &entry_MOUSECLICKLOCK, uiParam, pvParam, fWinIni );
2182 break;
2183 case SPI_GETMOUSEVANISH:
2184 ret = get_entry( &entry_MOUSEVANISH, uiParam, pvParam );
2185 break;
2186 case SPI_SETMOUSEVANISH:
2187 ret = set_entry( &entry_MOUSEVANISH, uiParam, pvParam, fWinIni );
2188 break;
2189 case SPI_GETFLATMENU:
2190 ret = get_entry( &entry_FLATMENU, uiParam, pvParam );
2191 break;
2192 case SPI_SETFLATMENU:
2193 ret = set_entry( &entry_FLATMENU, uiParam, pvParam, fWinIni );
2194 break;
2195 case SPI_GETDROPSHADOW:
2196 ret = get_entry( &entry_DROPSHADOW, uiParam, pvParam );
2197 break;
2198 case SPI_SETDROPSHADOW:
2199 ret = set_entry( &entry_DROPSHADOW, uiParam, pvParam, fWinIni );
2200 break;
2201 case SPI_GETBLOCKSENDINPUTRESETS:
2202 ret = get_entry( &entry_BLOCKSENDINPUTRESETS, uiParam, pvParam );
2203 break;
2204 case SPI_SETBLOCKSENDINPUTRESETS:
2205 ret = set_entry( &entry_BLOCKSENDINPUTRESETS, uiParam, pvParam, fWinIni );
2206 break;
2207 case SPI_GETUIEFFECTS:
2208 ret = get_entry( &entry_UIEFFECTS, uiParam, pvParam );
2209 break;
2210 case SPI_SETUIEFFECTS:
2211 /* FIXME: this probably should mask other UI effect values when unset */
2212 ret = set_entry( &entry_UIEFFECTS, uiParam, pvParam, fWinIni );
2213 break;
2214 case SPI_GETDISABLEOVERLAPPEDCONTENT:
2215 ret = get_entry( &entry_DISABLEOVERLAPPEDCONTENT, uiParam, pvParam );
2216 break;
2217 case SPI_SETDISABLEOVERLAPPEDCONTENT:
2218 ret = set_entry( &entry_DISABLEOVERLAPPEDCONTENT, uiParam, pvParam, fWinIni );
2219 break;
2220 case SPI_GETCLIENTAREAANIMATION:
2221 ret = get_entry( &entry_CLIENTAREAANIMATION, uiParam, pvParam );
2222 break;
2223 case SPI_SETCLIENTAREAANIMATION:
2224 ret = set_entry( &entry_CLIENTAREAANIMATION, uiParam, pvParam, fWinIni );
2225 break;
2226 case SPI_GETCLEARTYPE:
2227 ret = get_entry( &entry_CLEARTYPE, uiParam, pvParam );
2228 break;
2229 case SPI_SETCLEARTYPE:
2230 ret = set_entry( &entry_CLEARTYPE, uiParam, pvParam, fWinIni );
2231 break;
2232 case SPI_GETSPEECHRECOGNITION:
2233 ret = get_entry( &entry_SPEECHRECOGNITION, uiParam, pvParam );
2234 break;
2235 case SPI_SETSPEECHRECOGNITION:
2236 ret = set_entry( &entry_SPEECHRECOGNITION, uiParam, pvParam, fWinIni );
2237 break;
2238 case SPI_GETFOREGROUNDLOCKTIMEOUT:
2239 ret = get_entry( &entry_FOREGROUNDLOCKTIMEOUT, uiParam, pvParam );
2240 break;
2241 case SPI_SETFOREGROUNDLOCKTIMEOUT:
2242 /* FIXME: this should check that the calling thread
2243 * is able to change the foreground window */
2244 ret = set_entry( &entry_FOREGROUNDLOCKTIMEOUT, uiParam, pvParam, fWinIni );
2245 break;
2246 case SPI_GETACTIVEWNDTRKTIMEOUT:
2247 ret = get_entry( &entry_ACTIVEWNDTRKTIMEOUT, uiParam, pvParam );
2248 break;
2249 case SPI_SETACTIVEWNDTRKTIMEOUT:
2250 ret = get_entry( &entry_ACTIVEWNDTRKTIMEOUT, uiParam, pvParam );
2251 break;
2252 case SPI_GETFOREGROUNDFLASHCOUNT:
2253 ret = get_entry( &entry_FOREGROUNDFLASHCOUNT, uiParam, pvParam );
2254 break;
2255 case SPI_SETFOREGROUNDFLASHCOUNT:
2256 ret = set_entry( &entry_FOREGROUNDFLASHCOUNT, uiParam, pvParam, fWinIni );
2257 break;
2258 case SPI_GETCARETWIDTH:
2259 ret = get_entry( &entry_CARETWIDTH, uiParam, pvParam );
2260 break;
2261 case SPI_SETCARETWIDTH:
2262 ret = set_entry( &entry_CARETWIDTH, uiParam, pvParam, fWinIni );
2263 break;
2264 case SPI_GETMOUSECLICKLOCKTIME:
2265 ret = get_entry( &entry_MOUSECLICKLOCKTIME, uiParam, pvParam );
2266 break;
2267 case SPI_SETMOUSECLICKLOCKTIME:
2268 ret = set_entry( &entry_MOUSECLICKLOCKTIME, uiParam, pvParam, fWinIni );
2269 break;
2270 case SPI_GETFONTSMOOTHINGTYPE:
2271 ret = get_entry( &entry_FONTSMOOTHINGTYPE, uiParam, pvParam );
2272 break;
2273 case SPI_SETFONTSMOOTHINGTYPE:
2274 ret = set_entry( &entry_FONTSMOOTHINGTYPE, uiParam, pvParam, fWinIni );
2275 break;
2276 case SPI_GETFONTSMOOTHINGCONTRAST:
2277 ret = get_entry( &entry_FONTSMOOTHINGCONTRAST, uiParam, pvParam );
2278 break;
2279 case SPI_SETFONTSMOOTHINGCONTRAST:
2280 ret = set_entry( &entry_FONTSMOOTHINGCONTRAST, uiParam, pvParam, fWinIni );
2281 break;
2282 case SPI_GETFOCUSBORDERWIDTH:
2283 ret = get_entry( &entry_FOCUSBORDERWIDTH, uiParam, pvParam );
2284 break;
2285 case SPI_GETFOCUSBORDERHEIGHT:
2286 ret = get_entry( &entry_FOCUSBORDERHEIGHT, uiParam, pvParam );
2287 break;
2288 case SPI_SETFOCUSBORDERWIDTH:
2289 ret = set_entry( &entry_FOCUSBORDERWIDTH, uiParam, pvParam, fWinIni );
2290 break;
2291 case SPI_SETFOCUSBORDERHEIGHT:
2292 ret = set_entry( &entry_FOCUSBORDERHEIGHT, uiParam, pvParam, fWinIni );
2293 break;
2294 case SPI_GETFONTSMOOTHINGORIENTATION:
2295 ret = get_entry( &entry_FONTSMOOTHINGORIENTATION, uiParam, pvParam );
2296 break;
2297 case SPI_SETFONTSMOOTHINGORIENTATION:
2298 ret = set_entry( &entry_FONTSMOOTHINGORIENTATION, uiParam, pvParam, fWinIni );
2299 break;
2300 case SPI_GETAUDIODESCRIPTION:
2302 AUDIODESCRIPTION *audio = pvParam;
2303 if (audio && audio->cbSize == sizeof(AUDIODESCRIPTION) && uiParam == sizeof(AUDIODESCRIPTION) )
2305 ret = get_entry( &entry_AUDIODESC_ON, 0, &audio->Enabled ) &&
2306 get_entry( &entry_AUDIODESC_LOCALE, 0, &audio->Locale );
2308 break;
2310 case SPI_SETAUDIODESCRIPTION:
2312 AUDIODESCRIPTION *audio = pvParam;
2313 if (audio && audio->cbSize == sizeof(AUDIODESCRIPTION) && uiParam == sizeof(AUDIODESCRIPTION) )
2315 ret = set_entry( &entry_AUDIODESC_ON, 0, &audio->Enabled, fWinIni) &&
2316 set_entry( &entry_AUDIODESC_LOCALE, 0, &audio->Locale, fWinIni );
2318 break;
2320 default:
2321 FIXME( "Unknown action: %u\n", uiAction );
2322 SetLastError( ERROR_INVALID_SPI_VALUE );
2323 ret = FALSE;
2324 break;
2327 if (ret)
2328 SYSPARAMS_NotifyChange( uiAction, fWinIni );
2329 TRACE("(%u, %u, %p, %u) ret %d\n",
2330 uiAction, uiParam, pvParam, fWinIni, ret);
2331 return ret;
2333 #undef WINE_SPI_FIXME
2334 #undef WINE_SPI_WARN
2338 /***********************************************************************
2339 * SystemParametersInfoA (USER32.@)
2341 BOOL WINAPI SystemParametersInfoA( UINT uiAction, UINT uiParam,
2342 PVOID pvParam, UINT fuWinIni )
2344 BOOL ret;
2346 TRACE("(%u, %u, %p, %u)\n", uiAction, uiParam, pvParam, fuWinIni);
2348 switch (uiAction)
2350 case SPI_SETDESKWALLPAPER: /* 20 */
2351 case SPI_SETDESKPATTERN: /* 21 */
2353 WCHAR buffer[256];
2354 if (pvParam)
2355 if (!MultiByteToWideChar( CP_ACP, 0, pvParam, -1, buffer, ARRAY_SIZE( buffer )))
2356 buffer[ARRAY_SIZE(buffer)-1] = 0;
2357 ret = SystemParametersInfoW( uiAction, uiParam, pvParam ? buffer : NULL, fuWinIni );
2358 break;
2361 case SPI_GETICONTITLELOGFONT: /* 31 */
2363 LOGFONTW tmp;
2364 ret = SystemParametersInfoW( uiAction, uiParam, pvParam ? &tmp : NULL, fuWinIni );
2365 if (ret && pvParam)
2366 SYSPARAMS_LogFont32WTo32A( &tmp, pvParam );
2367 break;
2370 case SPI_GETNONCLIENTMETRICS: /* 41 WINVER >= 0x400 */
2372 NONCLIENTMETRICSW tmp;
2373 LPNONCLIENTMETRICSA lpnmA = pvParam;
2374 if (lpnmA && (lpnmA->cbSize == sizeof(NONCLIENTMETRICSA) ||
2375 lpnmA->cbSize == FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth)))
2377 tmp.cbSize = sizeof(NONCLIENTMETRICSW);
2378 ret = SystemParametersInfoW( uiAction, uiParam, &tmp, fuWinIni );
2379 if (ret)
2380 SYSPARAMS_NonClientMetrics32WTo32A( &tmp, lpnmA );
2382 else
2383 ret = FALSE;
2384 break;
2387 case SPI_SETNONCLIENTMETRICS: /* 42 WINVER >= 0x400 */
2389 NONCLIENTMETRICSW tmp;
2390 LPNONCLIENTMETRICSA lpnmA = pvParam;
2391 if (lpnmA && (lpnmA->cbSize == sizeof(NONCLIENTMETRICSA) ||
2392 lpnmA->cbSize == FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth)))
2394 tmp.cbSize = sizeof(NONCLIENTMETRICSW);
2395 SYSPARAMS_NonClientMetrics32ATo32W( lpnmA, &tmp );
2396 ret = SystemParametersInfoW( uiAction, uiParam, &tmp, fuWinIni );
2398 else
2399 ret = FALSE;
2400 break;
2403 case SPI_GETICONMETRICS: /* 45 WINVER >= 0x400 */
2405 ICONMETRICSW tmp;
2406 LPICONMETRICSA lpimA = pvParam;
2407 if (lpimA && lpimA->cbSize == sizeof(ICONMETRICSA))
2409 tmp.cbSize = sizeof(ICONMETRICSW);
2410 ret = SystemParametersInfoW( uiAction, uiParam, &tmp, fuWinIni );
2411 if (ret)
2413 lpimA->iHorzSpacing = tmp.iHorzSpacing;
2414 lpimA->iVertSpacing = tmp.iVertSpacing;
2415 lpimA->iTitleWrap = tmp.iTitleWrap;
2416 SYSPARAMS_LogFont32WTo32A( &tmp.lfFont, &lpimA->lfFont );
2419 else
2420 ret = FALSE;
2421 break;
2424 case SPI_SETICONMETRICS: /* 46 WINVER >= 0x400 */
2426 ICONMETRICSW tmp;
2427 LPICONMETRICSA lpimA = pvParam;
2428 if (lpimA && lpimA->cbSize == sizeof(ICONMETRICSA))
2430 tmp.cbSize = sizeof(ICONMETRICSW);
2431 tmp.iHorzSpacing = lpimA->iHorzSpacing;
2432 tmp.iVertSpacing = lpimA->iVertSpacing;
2433 tmp.iTitleWrap = lpimA->iTitleWrap;
2434 SYSPARAMS_LogFont32ATo32W( &lpimA->lfFont, &tmp.lfFont);
2435 ret = SystemParametersInfoW( uiAction, uiParam, &tmp, fuWinIni );
2437 else
2438 ret = FALSE;
2439 break;
2442 case SPI_GETHIGHCONTRAST: /* 66 WINVER >= 0x400 */
2444 HIGHCONTRASTW tmp;
2445 LPHIGHCONTRASTA lphcA = pvParam;
2446 if (lphcA && lphcA->cbSize == sizeof(HIGHCONTRASTA))
2448 tmp.cbSize = sizeof(HIGHCONTRASTW);
2449 ret = SystemParametersInfoW( uiAction, uiParam, &tmp, fuWinIni );
2450 if (ret)
2452 lphcA->dwFlags = tmp.dwFlags;
2453 lphcA->lpszDefaultScheme = NULL; /* FIXME? */
2456 else
2457 ret = FALSE;
2458 break;
2461 case SPI_GETDESKWALLPAPER: /* 115 */
2463 WCHAR buffer[MAX_PATH];
2464 ret = (SystemParametersInfoW( SPI_GETDESKWALLPAPER, uiParam, buffer, fuWinIni ) &&
2465 WideCharToMultiByte(CP_ACP, 0, buffer, -1, pvParam, uiParam, NULL, NULL));
2466 break;
2469 default:
2470 ret = SystemParametersInfoW( uiAction, uiParam, pvParam, fuWinIni );
2471 break;
2473 return ret;
2477 /***********************************************************************
2478 * GetSystemMetrics (USER32.@)
2480 INT WINAPI GetSystemMetrics( INT index )
2482 struct monitor_info info;
2483 NONCLIENTMETRICSW ncm;
2484 MINIMIZEDMETRICS mm;
2485 ICONMETRICSW im;
2486 UINT ret;
2487 HDC hdc;
2489 /* some metrics are dynamic */
2490 switch (index)
2492 case SM_CXVSCROLL:
2493 case SM_CYHSCROLL:
2494 get_entry( &entry_SCROLLWIDTH, 0, &ret );
2495 return max( ret, 8 );
2496 case SM_CYCAPTION:
2497 ncm.cbSize = sizeof(ncm);
2498 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2499 return ncm.iCaptionHeight + 1;
2500 case SM_CXBORDER:
2501 case SM_CYBORDER:
2502 /* SM_C{X,Y}BORDER always returns 1 regardless of 'BorderWidth' value in registry */
2503 return 1;
2504 case SM_CXDLGFRAME:
2505 case SM_CYDLGFRAME:
2506 return 3;
2507 case SM_CYVTHUMB:
2508 case SM_CXHTHUMB:
2509 case SM_CYVSCROLL:
2510 case SM_CXHSCROLL:
2511 get_entry( &entry_SCROLLHEIGHT, 0, &ret );
2512 return max( ret, 8 );
2513 case SM_CXICON:
2514 case SM_CYICON:
2515 return map_to_dpi( 32, GetDpiForSystem() );
2516 case SM_CXCURSOR:
2517 case SM_CYCURSOR:
2518 ret = map_to_dpi( 32, GetDpiForSystem() );
2519 if (ret >= 64) return 64;
2520 if (ret >= 48) return 48;
2521 return 32;
2522 case SM_CYMENU:
2523 ncm.cbSize = sizeof(ncm);
2524 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2525 return ncm.iMenuHeight + 1;
2526 case SM_CXFULLSCREEN:
2527 /* see the remark for SM_CXMAXIMIZED, at least this formulation is
2528 * correct */
2529 return GetSystemMetrics( SM_CXMAXIMIZED) - 2 * GetSystemMetrics( SM_CXFRAME);
2530 case SM_CYFULLSCREEN:
2531 /* see the remark for SM_CYMAXIMIZED, at least this formulation is
2532 * correct */
2533 return GetSystemMetrics( SM_CYMAXIMIZED) - GetSystemMetrics( SM_CYMIN);
2534 case SM_CYKANJIWINDOW:
2535 return 0;
2536 case SM_MOUSEPRESENT:
2537 return 1;
2538 case SM_DEBUG:
2539 return 0;
2540 case SM_SWAPBUTTON:
2541 get_entry( &entry_MOUSEBUTTONSWAP, 0, &ret );
2542 return ret;
2543 case SM_RESERVED1:
2544 case SM_RESERVED2:
2545 case SM_RESERVED3:
2546 case SM_RESERVED4:
2547 return 0;
2548 case SM_CXMIN:
2549 ncm.cbSize = sizeof(ncm);
2550 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2551 hdc = get_display_dc();
2552 get_text_metr_size( hdc, &ncm.lfCaptionFont, NULL, &ret );
2553 release_display_dc( hdc );
2554 return 3 * ncm.iCaptionWidth + ncm.iCaptionHeight + 4 * ret + 2 * GetSystemMetrics(SM_CXFRAME) + 4;
2555 case SM_CYMIN:
2556 return GetSystemMetrics( SM_CYCAPTION) + 2 * GetSystemMetrics( SM_CYFRAME);
2557 case SM_CXSIZE:
2558 get_entry( &entry_CAPTIONWIDTH, 0, &ret );
2559 return max( ret, 8 );
2560 case SM_CYSIZE:
2561 ncm.cbSize = sizeof(ncm);
2562 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2563 return ncm.iCaptionHeight;
2564 case SM_CXFRAME:
2565 get_entry( &entry_BORDER, 0, &ret );
2566 ret = max( ret, 1 );
2567 return GetSystemMetrics(SM_CXDLGFRAME) + ret;
2568 case SM_CYFRAME:
2569 get_entry( &entry_BORDER, 0, &ret );
2570 ret = max( ret, 1 );
2571 return GetSystemMetrics(SM_CYDLGFRAME) + ret;
2572 case SM_CXMINTRACK:
2573 return GetSystemMetrics(SM_CXMIN);
2574 case SM_CYMINTRACK:
2575 return GetSystemMetrics(SM_CYMIN);
2576 case SM_CXDOUBLECLK:
2577 get_entry( &entry_DOUBLECLKWIDTH, 0, &ret );
2578 return ret;
2579 case SM_CYDOUBLECLK:
2580 get_entry( &entry_DOUBLECLKHEIGHT, 0, &ret );
2581 return ret;
2582 case SM_CXICONSPACING:
2583 im.cbSize = sizeof(im);
2584 SystemParametersInfoW( SPI_GETICONMETRICS, sizeof(im), &im, 0 );
2585 return im.iHorzSpacing;
2586 case SM_CYICONSPACING:
2587 im.cbSize = sizeof(im);
2588 SystemParametersInfoW( SPI_GETICONMETRICS, sizeof(im), &im, 0 );
2589 return im.iVertSpacing;
2590 case SM_MENUDROPALIGNMENT:
2591 SystemParametersInfoW( SPI_GETMENUDROPALIGNMENT, 0, &ret, 0 );
2592 return ret;
2593 case SM_PENWINDOWS:
2594 return 0;
2595 case SM_DBCSENABLED:
2597 CPINFO cpinfo;
2598 GetCPInfo( CP_ACP, &cpinfo );
2599 return (cpinfo.MaxCharSize > 1);
2601 case SM_CMOUSEBUTTONS:
2602 return 3;
2603 case SM_SECURE:
2604 return 0;
2605 case SM_CXEDGE:
2606 return GetSystemMetrics(SM_CXBORDER) + 1;
2607 case SM_CYEDGE:
2608 return GetSystemMetrics(SM_CYBORDER) + 1;
2609 case SM_CXMINSPACING:
2610 mm.cbSize = sizeof(mm);
2611 SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
2612 return GetSystemMetrics(SM_CXMINIMIZED) + mm.iHorzGap;
2613 case SM_CYMINSPACING:
2614 mm.cbSize = sizeof(mm);
2615 SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
2616 return GetSystemMetrics(SM_CYMINIMIZED) + mm.iVertGap;
2617 case SM_CXSMICON:
2618 case SM_CYSMICON:
2619 return map_to_dpi( 16, GetDpiForSystem() ) & ~1;
2620 case SM_CYSMCAPTION:
2621 ncm.cbSize = sizeof(ncm);
2622 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2623 return ncm.iSmCaptionHeight + 1;
2624 case SM_CXSMSIZE:
2625 get_entry( &entry_SMCAPTIONWIDTH, 0, &ret );
2626 return ret;
2627 case SM_CYSMSIZE:
2628 ncm.cbSize = sizeof(ncm);
2629 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2630 return ncm.iSmCaptionHeight;
2631 case SM_CXMENUSIZE:
2632 get_entry( &entry_MENUWIDTH, 0, &ret );
2633 return ret;
2634 case SM_CYMENUSIZE:
2635 ncm.cbSize = sizeof(ncm);
2636 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2637 return ncm.iMenuHeight;
2638 case SM_ARRANGE:
2639 mm.cbSize = sizeof(mm);
2640 SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
2641 return mm.iArrange;
2642 case SM_CXMINIMIZED:
2643 mm.cbSize = sizeof(mm);
2644 SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
2645 return mm.iWidth + 6;
2646 case SM_CYMINIMIZED:
2647 ncm.cbSize = sizeof(ncm);
2648 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2649 return ncm.iCaptionHeight + 6;
2650 case SM_CXMAXTRACK:
2651 return GetSystemMetrics(SM_CXVIRTUALSCREEN) + 4 + 2 * GetSystemMetrics(SM_CXFRAME);
2652 case SM_CYMAXTRACK:
2653 return GetSystemMetrics(SM_CYVIRTUALSCREEN) + 4 + 2 * GetSystemMetrics(SM_CYFRAME);
2654 case SM_CXMAXIMIZED:
2655 /* FIXME: subtract the width of any vertical application toolbars*/
2656 return GetSystemMetrics(SM_CXSCREEN) + 2 * GetSystemMetrics(SM_CXFRAME);
2657 case SM_CYMAXIMIZED:
2658 /* FIXME: subtract the width of any horizontal application toolbars*/
2659 return GetSystemMetrics(SM_CYSCREEN) + 2 * GetSystemMetrics(SM_CYCAPTION);
2660 case SM_NETWORK:
2661 return 3; /* FIXME */
2662 case SM_CLEANBOOT:
2663 return 0; /* 0 = ok, 1 = failsafe, 2 = failsafe + network */
2664 case SM_CXDRAG:
2665 get_entry( &entry_DRAGWIDTH, 0, &ret );
2666 return ret;
2667 case SM_CYDRAG:
2668 get_entry( &entry_DRAGHEIGHT, 0, &ret );
2669 return ret;
2670 case SM_SHOWSOUNDS:
2671 get_entry( &entry_SHOWSOUNDS, 0, &ret );
2672 return ret;
2673 case SM_CXMENUCHECK:
2674 case SM_CYMENUCHECK:
2676 TEXTMETRICW tm;
2677 ncm.cbSize = sizeof(ncm);
2678 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2679 hdc = get_display_dc();
2680 get_text_metr_size( hdc, &ncm.lfMenuFont, &tm, NULL);
2681 release_display_dc( hdc );
2682 return tm.tmHeight <= 0 ? 13 : ((tm.tmHeight + tm.tmExternalLeading + 1) / 2) * 2 - 1;
2684 case SM_SLOWMACHINE:
2685 return 0; /* Never true */
2686 case SM_MIDEASTENABLED:
2687 return 0; /* FIXME */
2688 case SM_MOUSEWHEELPRESENT:
2689 return 1;
2690 case SM_CXSCREEN:
2691 get_monitors_info( &info );
2692 return info.primary_rect.right - info.primary_rect.left;
2693 case SM_CYSCREEN:
2694 get_monitors_info( &info );
2695 return info.primary_rect.bottom - info.primary_rect.top;
2696 case SM_XVIRTUALSCREEN:
2697 get_monitors_info( &info );
2698 return info.virtual_rect.left;
2699 case SM_YVIRTUALSCREEN:
2700 get_monitors_info( &info );
2701 return info.virtual_rect.top;
2702 case SM_CXVIRTUALSCREEN:
2703 get_monitors_info( &info );
2704 return info.virtual_rect.right - info.virtual_rect.left;
2705 case SM_CYVIRTUALSCREEN:
2706 get_monitors_info( &info );
2707 return info.virtual_rect.bottom - info.virtual_rect.top;
2708 case SM_CMONITORS:
2709 get_monitors_info( &info );
2710 return info.count;
2711 case SM_SAMEDISPLAYFORMAT:
2712 return 1;
2713 case SM_IMMENABLED:
2714 return 0; /* FIXME */
2715 case SM_CXFOCUSBORDER:
2716 case SM_CYFOCUSBORDER:
2717 return 1;
2718 case SM_TABLETPC:
2719 case SM_MEDIACENTER:
2720 return 0;
2721 case SM_CMETRICS:
2722 return SM_CMETRICS;
2723 default:
2724 return 0;
2729 /***********************************************************************
2730 * GetSystemMetricsForDpi (USER32.@)
2732 INT WINAPI GetSystemMetricsForDpi( INT index, UINT dpi )
2734 NONCLIENTMETRICSW ncm;
2735 ICONMETRICSW im;
2736 UINT ret;
2737 HDC hdc;
2739 /* some metrics are dynamic */
2740 switch (index)
2742 case SM_CXVSCROLL:
2743 case SM_CYHSCROLL:
2744 get_entry_dpi( &entry_SCROLLWIDTH, 0, &ret, dpi );
2745 return max( ret, 8 );
2746 case SM_CYCAPTION:
2747 ncm.cbSize = sizeof(ncm);
2748 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2749 return ncm.iCaptionHeight + 1;
2750 case SM_CYVTHUMB:
2751 case SM_CXHTHUMB:
2752 case SM_CYVSCROLL:
2753 case SM_CXHSCROLL:
2754 get_entry_dpi( &entry_SCROLLHEIGHT, 0, &ret, dpi );
2755 return max( ret, 8 );
2756 case SM_CXICON:
2757 case SM_CYICON:
2758 return map_to_dpi( 32, dpi );
2759 case SM_CXCURSOR:
2760 case SM_CYCURSOR:
2761 ret = map_to_dpi( 32, dpi );
2762 if (ret >= 64) return 64;
2763 if (ret >= 48) return 48;
2764 return 32;
2765 case SM_CYMENU:
2766 ncm.cbSize = sizeof(ncm);
2767 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2768 return ncm.iMenuHeight + 1;
2769 case SM_CXSIZE:
2770 get_entry_dpi( &entry_CAPTIONWIDTH, 0, &ret, dpi );
2771 return max( ret, 8 );
2772 case SM_CYSIZE:
2773 ncm.cbSize = sizeof(ncm);
2774 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2775 return ncm.iCaptionHeight;
2776 case SM_CXFRAME:
2777 get_entry_dpi( &entry_BORDER, 0, &ret, dpi );
2778 ret = max( ret, 1 );
2779 return GetSystemMetricsForDpi( SM_CXDLGFRAME, dpi ) + ret;
2780 case SM_CYFRAME:
2781 get_entry_dpi( &entry_BORDER, 0, &ret, dpi );
2782 ret = max( ret, 1 );
2783 return GetSystemMetricsForDpi( SM_CYDLGFRAME, dpi ) + ret;
2784 case SM_CXICONSPACING:
2785 im.cbSize = sizeof(im);
2786 SystemParametersInfoForDpi( SPI_GETICONMETRICS, sizeof(im), &im, 0, dpi );
2787 return im.iHorzSpacing;
2788 case SM_CYICONSPACING:
2789 im.cbSize = sizeof(im);
2790 SystemParametersInfoForDpi( SPI_GETICONMETRICS, sizeof(im), &im, 0, dpi );
2791 return im.iVertSpacing;
2792 case SM_CXSMICON:
2793 case SM_CYSMICON:
2794 return map_to_dpi( 16, dpi ) & ~1;
2795 case SM_CYSMCAPTION:
2796 ncm.cbSize = sizeof(ncm);
2797 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2798 return ncm.iSmCaptionHeight + 1;
2799 case SM_CXSMSIZE:
2800 get_entry_dpi( &entry_SMCAPTIONWIDTH, 0, &ret, dpi );
2801 return ret;
2802 case SM_CYSMSIZE:
2803 ncm.cbSize = sizeof(ncm);
2804 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2805 return ncm.iSmCaptionHeight;
2806 case SM_CXMENUSIZE:
2807 get_entry_dpi( &entry_MENUWIDTH, 0, &ret, dpi );
2808 return ret;
2809 case SM_CYMENUSIZE:
2810 ncm.cbSize = sizeof(ncm);
2811 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2812 return ncm.iMenuHeight;
2813 case SM_CXMENUCHECK:
2814 case SM_CYMENUCHECK:
2816 TEXTMETRICW tm;
2817 ncm.cbSize = sizeof(ncm);
2818 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2819 hdc = get_display_dc();
2820 get_text_metr_size( hdc, &ncm.lfMenuFont, &tm, NULL);
2821 release_display_dc( hdc );
2822 return tm.tmHeight <= 0 ? 13 : ((tm.tmHeight + tm.tmExternalLeading - 1) | 1);
2824 default:
2825 return GetSystemMetrics( index );
2830 /***********************************************************************
2831 * SwapMouseButton (USER32.@)
2832 * Reverse or restore the meaning of the left and right mouse buttons
2833 * fSwap [I ] TRUE - reverse, FALSE - original
2834 * RETURN
2835 * previous state
2837 BOOL WINAPI SwapMouseButton( BOOL fSwap )
2839 BOOL prev = GetSystemMetrics(SM_SWAPBUTTON);
2840 SystemParametersInfoW(SPI_SETMOUSEBUTTONSWAP, fSwap, 0, 0);
2841 return prev;
2845 /**********************************************************************
2846 * SetDoubleClickTime (USER32.@)
2848 BOOL WINAPI SetDoubleClickTime( UINT interval )
2850 return SystemParametersInfoW(SPI_SETDOUBLECLICKTIME, interval, 0, 0);
2854 /**********************************************************************
2855 * GetDoubleClickTime (USER32.@)
2857 UINT WINAPI GetDoubleClickTime(void)
2859 UINT time = 0;
2861 get_entry( &entry_DOUBLECLICKTIME, 0, &time );
2862 if (!time) time = 500;
2863 return time;
2867 /*************************************************************************
2868 * GetSysColor (USER32.@)
2870 COLORREF WINAPI DECLSPEC_HOTPATCH GetSysColor( INT nIndex )
2872 COLORREF ret = 0;
2874 if (nIndex >= 0 && nIndex < ARRAY_SIZE( system_colors ))
2875 get_entry( &system_colors[nIndex], 0, &ret );
2876 return ret;
2880 /*************************************************************************
2881 * SetSysColors (USER32.@)
2883 BOOL WINAPI SetSysColors( INT count, const INT *colors, const COLORREF *values )
2885 int i;
2887 if (IS_INTRESOURCE(colors)) return FALSE; /* stupid app passes a color instead of an array */
2889 for (i = 0; i < count; i++)
2890 if (colors[i] >= 0 && colors[i] <= ARRAY_SIZE( system_colors ))
2891 set_entry( &system_colors[colors[i]], values[i], 0, 0 );
2893 /* Send WM_SYSCOLORCHANGE message to all windows */
2895 SendMessageTimeoutW( HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0, SMTO_ABORTIFHUNG, 2000, NULL );
2897 /* Repaint affected portions of all visible windows */
2899 RedrawWindow( 0, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN );
2900 return TRUE;
2904 /*************************************************************************
2905 * SetSysColorsTemp (USER32.@)
2907 DWORD_PTR WINAPI SetSysColorsTemp( const COLORREF *pPens, const HBRUSH *pBrushes, DWORD_PTR n)
2909 FIXME( "no longer supported\n" );
2910 return FALSE;
2914 /***********************************************************************
2915 * GetSysColorBrush (USER32.@)
2917 HBRUSH WINAPI DECLSPEC_HOTPATCH GetSysColorBrush( INT index )
2919 if (index < 0 || index >= ARRAY_SIZE( system_colors )) return 0;
2921 if (!system_colors[index].brush)
2923 HBRUSH brush = CreateSolidBrush( GetSysColor( index ));
2924 __wine_make_gdi_object_system( brush, TRUE );
2925 if (InterlockedCompareExchangePointer( (void **)&system_colors[index].brush, brush, 0 ))
2927 __wine_make_gdi_object_system( brush, FALSE );
2928 DeleteObject( brush );
2931 return system_colors[index].brush;
2935 /***********************************************************************
2936 * SYSCOLOR_GetPen
2938 HPEN SYSCOLOR_GetPen( INT index )
2940 /* We can assert here, because this function is internal to Wine */
2941 assert (0 <= index && index < ARRAY_SIZE( system_colors ));
2943 if (!system_colors[index].pen)
2945 HPEN pen = CreatePen( PS_SOLID, 1, GetSysColor( index ));
2946 __wine_make_gdi_object_system( pen, TRUE );
2947 if (InterlockedCompareExchangePointer( (void **)&system_colors[index].pen, pen, 0 ))
2949 __wine_make_gdi_object_system( pen, FALSE );
2950 DeleteObject( pen );
2953 return system_colors[index].pen;
2957 /***********************************************************************
2958 * SYSCOLOR_Get55AABrush
2960 HBRUSH SYSCOLOR_Get55AABrush(void)
2962 static const WORD pattern[] = { 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa };
2963 static HBRUSH brush_55aa;
2965 if (!brush_55aa)
2967 HBITMAP bitmap = CreateBitmap( 8, 8, 1, 1, pattern );
2968 HBRUSH brush = CreatePatternBrush( bitmap );
2969 DeleteObject( bitmap );
2970 __wine_make_gdi_object_system( brush, TRUE );
2971 if (InterlockedCompareExchangePointer( (void **)&brush_55aa, brush, 0 ))
2973 __wine_make_gdi_object_system( brush, FALSE );
2974 DeleteObject( brush );
2977 return brush_55aa;
2980 /***********************************************************************
2981 * ChangeDisplaySettingsA (USER32.@)
2983 LONG WINAPI ChangeDisplaySettingsA( LPDEVMODEA devmode, DWORD flags )
2985 if (devmode) devmode->dmDriverExtra = 0;
2987 return ChangeDisplaySettingsExA(NULL,devmode,NULL,flags,NULL);
2991 /***********************************************************************
2992 * ChangeDisplaySettingsW (USER32.@)
2994 LONG WINAPI ChangeDisplaySettingsW( LPDEVMODEW devmode, DWORD flags )
2996 if (devmode) devmode->dmDriverExtra = 0;
2998 return ChangeDisplaySettingsExW(NULL,devmode,NULL,flags,NULL);
3002 /***********************************************************************
3003 * ChangeDisplaySettingsExA (USER32.@)
3005 LONG WINAPI ChangeDisplaySettingsExA( LPCSTR devname, LPDEVMODEA devmode, HWND hwnd,
3006 DWORD flags, LPVOID lparam )
3008 LONG ret;
3009 UNICODE_STRING nameW;
3011 if (devname) RtlCreateUnicodeStringFromAsciiz(&nameW, devname);
3012 else nameW.Buffer = NULL;
3014 if (devmode)
3016 DEVMODEW *devmodeW;
3018 devmodeW = GdiConvertToDevmodeW(devmode);
3019 if (devmodeW)
3021 ret = ChangeDisplaySettingsExW(nameW.Buffer, devmodeW, hwnd, flags, lparam);
3022 HeapFree(GetProcessHeap(), 0, devmodeW);
3024 else
3025 ret = DISP_CHANGE_SUCCESSFUL;
3027 else
3029 ret = ChangeDisplaySettingsExW(nameW.Buffer, NULL, hwnd, flags, lparam);
3032 if (devname) RtlFreeUnicodeString(&nameW);
3033 return ret;
3036 #define _X_FIELD(prefix, bits) \
3037 if ((fields) & prefix##_##bits) \
3039 p += sprintf(p, "%s%s", first ? "" : ",", #bits); \
3040 first = FALSE; \
3043 static const CHAR *_CDS_flags(DWORD fields)
3045 BOOL first = TRUE;
3046 CHAR buf[128];
3047 CHAR *p = buf;
3049 _X_FIELD(CDS, UPDATEREGISTRY)
3050 _X_FIELD(CDS, TEST)
3051 _X_FIELD(CDS, FULLSCREEN)
3052 _X_FIELD(CDS, GLOBAL)
3053 _X_FIELD(CDS, SET_PRIMARY)
3054 _X_FIELD(CDS, VIDEOPARAMETERS)
3055 _X_FIELD(CDS, ENABLE_UNSAFE_MODES)
3056 _X_FIELD(CDS, DISABLE_UNSAFE_MODES)
3057 _X_FIELD(CDS, RESET)
3058 _X_FIELD(CDS, RESET_EX)
3059 _X_FIELD(CDS, NORESET)
3061 *p = 0;
3062 return wine_dbg_sprintf("%s", buf);
3065 static const CHAR *_DM_fields(DWORD fields)
3067 BOOL first = TRUE;
3068 CHAR buf[128];
3069 CHAR *p = buf;
3071 _X_FIELD(DM, BITSPERPEL)
3072 _X_FIELD(DM, PELSWIDTH)
3073 _X_FIELD(DM, PELSHEIGHT)
3074 _X_FIELD(DM, DISPLAYFLAGS)
3075 _X_FIELD(DM, DISPLAYFREQUENCY)
3076 _X_FIELD(DM, POSITION)
3077 _X_FIELD(DM, DISPLAYORIENTATION)
3079 *p = 0;
3080 return wine_dbg_sprintf("%s", buf);
3083 #undef _X_FIELD
3085 static void trace_devmode(const DEVMODEW *devmode)
3087 TRACE("dmFields=%s ", _DM_fields(devmode->dmFields));
3088 if (devmode->dmFields & DM_BITSPERPEL)
3089 TRACE("dmBitsPerPel=%u ", devmode->dmBitsPerPel);
3090 if (devmode->dmFields & DM_PELSWIDTH)
3091 TRACE("dmPelsWidth=%u ", devmode->dmPelsWidth);
3092 if (devmode->dmFields & DM_PELSHEIGHT)
3093 TRACE("dmPelsHeight=%u ", devmode->dmPelsHeight);
3094 if (devmode->dmFields & DM_DISPLAYFREQUENCY)
3095 TRACE("dmDisplayFrequency=%u ", devmode->dmDisplayFrequency);
3096 if (devmode->dmFields & DM_POSITION)
3097 TRACE("dmPosition=(%d,%d) ", devmode->u1.s2.dmPosition.x, devmode->u1.s2.dmPosition.y);
3098 if (devmode->dmFields & DM_DISPLAYFLAGS)
3099 TRACE("dmDisplayFlags=%#x ", devmode->u2.dmDisplayFlags);
3100 if (devmode->dmFields & DM_DISPLAYORIENTATION)
3101 TRACE("dmDisplayOrientation=%u ", devmode->u1.s2.dmDisplayOrientation);
3102 TRACE("\n");
3105 static BOOL is_detached_mode(const DEVMODEW *mode)
3107 return mode->dmFields & DM_POSITION &&
3108 mode->dmFields & DM_PELSWIDTH &&
3109 mode->dmFields & DM_PELSHEIGHT &&
3110 mode->dmPelsWidth == 0 &&
3111 mode->dmPelsHeight == 0;
3114 /***********************************************************************
3115 * ChangeDisplaySettingsExW (USER32.@)
3117 LONG WINAPI ChangeDisplaySettingsExW( LPCWSTR devname, LPDEVMODEW devmode, HWND hwnd,
3118 DWORD flags, LPVOID lparam )
3120 WCHAR primary_adapter[CCHDEVICENAME];
3121 BOOL def_mode = TRUE;
3122 DEVMODEW dm;
3123 LONG ret;
3125 TRACE("%s %p %p %#x %p\n", debugstr_w(devname), devmode, hwnd, flags, lparam);
3126 TRACE("flags=%s\n", _CDS_flags(flags));
3128 if (!devname && !devmode)
3130 ret = USER_Driver->pChangeDisplaySettingsEx(NULL, NULL, hwnd, flags, lparam);
3131 if (ret != DISP_CHANGE_SUCCESSFUL)
3132 ERR("Restoring all displays to their registry settings returned %d.\n", ret);
3133 return ret;
3136 if (!devname && devmode)
3138 if (!get_primary_adapter(primary_adapter))
3139 return DISP_CHANGE_FAILED;
3141 devname = primary_adapter;
3144 if (!is_valid_adapter_name(devname))
3146 ERR("Invalid device name %s.\n", wine_dbgstr_w(devname));
3147 return DISP_CHANGE_BADPARAM;
3150 if (devmode)
3152 trace_devmode(devmode);
3154 if (devmode->dmSize < FIELD_OFFSET(DEVMODEW, dmICMMethod))
3155 return DISP_CHANGE_BADMODE;
3157 if (is_detached_mode(devmode) ||
3158 ((devmode->dmFields & DM_BITSPERPEL) && devmode->dmBitsPerPel) ||
3159 ((devmode->dmFields & DM_PELSWIDTH) && devmode->dmPelsWidth) ||
3160 ((devmode->dmFields & DM_PELSHEIGHT) && devmode->dmPelsHeight) ||
3161 ((devmode->dmFields & DM_DISPLAYFREQUENCY) && devmode->dmDisplayFrequency))
3162 def_mode = FALSE;
3165 if (def_mode)
3167 memset(&dm, 0, sizeof(dm));
3168 dm.dmSize = sizeof(dm);
3169 if (!EnumDisplaySettingsExW(devname, ENUM_REGISTRY_SETTINGS, &dm, 0))
3171 ERR("Default mode not found!\n");
3172 return DISP_CHANGE_BADMODE;
3175 TRACE("Return to original display mode\n");
3176 devmode = &dm;
3179 if ((devmode->dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != (DM_PELSWIDTH | DM_PELSHEIGHT))
3181 WARN("devmode doesn't specify the resolution: %#x\n", devmode->dmFields);
3182 return DISP_CHANGE_BADMODE;
3185 if (!is_detached_mode(devmode) && (!devmode->dmPelsWidth || !devmode->dmPelsHeight))
3187 memset(&dm, 0, sizeof(dm));
3188 dm.dmSize = sizeof(dm);
3189 if (!EnumDisplaySettingsExW(devname, ENUM_CURRENT_SETTINGS, &dm, 0))
3191 ERR("Current mode not found!\n");
3192 return DISP_CHANGE_BADMODE;
3195 if (!devmode->dmPelsWidth)
3196 devmode->dmPelsWidth = dm.dmPelsWidth;
3197 if (!devmode->dmPelsHeight)
3198 devmode->dmPelsHeight = dm.dmPelsHeight;
3201 ret = USER_Driver->pChangeDisplaySettingsEx(devname, devmode, hwnd, flags, lparam);
3202 if (ret != DISP_CHANGE_SUCCESSFUL)
3203 ERR("Changing %s display settings returned %d.\n", wine_dbgstr_w(devname), ret);
3204 return ret;
3208 /***********************************************************************
3209 * EnumDisplaySettingsW (USER32.@)
3211 * RETURNS
3212 * TRUE if nth setting exists found (described in the LPDEVMODEW struct)
3213 * FALSE if we do not have the nth setting
3215 BOOL WINAPI EnumDisplaySettingsW( LPCWSTR name, DWORD n, LPDEVMODEW devmode )
3217 return EnumDisplaySettingsExW(name, n, devmode, 0);
3221 /***********************************************************************
3222 * EnumDisplaySettingsA (USER32.@)
3224 BOOL WINAPI EnumDisplaySettingsA(LPCSTR name,DWORD n,LPDEVMODEA devmode)
3226 return EnumDisplaySettingsExA(name, n, devmode, 0);
3230 /***********************************************************************
3231 * EnumDisplaySettingsExA (USER32.@)
3233 BOOL WINAPI EnumDisplaySettingsExA(LPCSTR lpszDeviceName, DWORD iModeNum,
3234 LPDEVMODEA lpDevMode, DWORD dwFlags)
3236 DEVMODEW devmodeW;
3237 BOOL ret;
3238 UNICODE_STRING nameW;
3240 if (lpszDeviceName) RtlCreateUnicodeStringFromAsciiz(&nameW, lpszDeviceName);
3241 else nameW.Buffer = NULL;
3243 memset(&devmodeW, 0, sizeof(devmodeW));
3244 devmodeW.dmSize = sizeof(devmodeW);
3245 ret = EnumDisplaySettingsExW(nameW.Buffer,iModeNum,&devmodeW,dwFlags);
3246 if (ret)
3248 lpDevMode->dmSize = FIELD_OFFSET(DEVMODEA, dmICMMethod);
3249 lpDevMode->dmSpecVersion = devmodeW.dmSpecVersion;
3250 lpDevMode->dmDriverVersion = devmodeW.dmDriverVersion;
3251 WideCharToMultiByte(CP_ACP, 0, devmodeW.dmDeviceName, -1,
3252 (LPSTR)lpDevMode->dmDeviceName, CCHDEVICENAME, NULL, NULL);
3253 lpDevMode->dmDriverExtra = 0; /* FIXME */
3254 lpDevMode->dmBitsPerPel = devmodeW.dmBitsPerPel;
3255 lpDevMode->dmPelsHeight = devmodeW.dmPelsHeight;
3256 lpDevMode->dmPelsWidth = devmodeW.dmPelsWidth;
3257 lpDevMode->u2.dmDisplayFlags = devmodeW.u2.dmDisplayFlags;
3258 lpDevMode->dmDisplayFrequency = devmodeW.dmDisplayFrequency;
3259 lpDevMode->dmFields = devmodeW.dmFields;
3261 lpDevMode->u1.s2.dmPosition.x = devmodeW.u1.s2.dmPosition.x;
3262 lpDevMode->u1.s2.dmPosition.y = devmodeW.u1.s2.dmPosition.y;
3263 lpDevMode->u1.s2.dmDisplayOrientation = devmodeW.u1.s2.dmDisplayOrientation;
3264 lpDevMode->u1.s2.dmDisplayFixedOutput = devmodeW.u1.s2.dmDisplayFixedOutput;
3266 if (lpszDeviceName) RtlFreeUnicodeString(&nameW);
3267 return ret;
3271 /***********************************************************************
3272 * EnumDisplaySettingsExW (USER32.@)
3274 BOOL WINAPI EnumDisplaySettingsExW(LPCWSTR lpszDeviceName, DWORD iModeNum,
3275 LPDEVMODEW lpDevMode, DWORD dwFlags)
3277 WCHAR primary_adapter[CCHDEVICENAME];
3278 BOOL ret;
3280 TRACE("%s %#x %p %#x\n", wine_dbgstr_w(lpszDeviceName), iModeNum, lpDevMode, dwFlags);
3282 if (!lpszDeviceName)
3284 if (!get_primary_adapter(primary_adapter))
3285 return FALSE;
3287 lpszDeviceName = primary_adapter;
3290 if (!is_valid_adapter_name(lpszDeviceName))
3292 ERR("Invalid device name %s.\n", wine_dbgstr_w(lpszDeviceName));
3293 return FALSE;
3296 ret = USER_Driver->pEnumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, dwFlags);
3297 if (ret)
3298 TRACE("device:%s mode index:%#x position:(%d,%d) resolution:%ux%u frequency:%uHz "
3299 "depth:%ubits orientation:%#x.\n", wine_dbgstr_w(lpszDeviceName), iModeNum,
3300 lpDevMode->u1.s2.dmPosition.x, lpDevMode->u1.s2.dmPosition.y, lpDevMode->dmPelsWidth,
3301 lpDevMode->dmPelsHeight, lpDevMode->dmDisplayFrequency, lpDevMode->dmBitsPerPel,
3302 lpDevMode->u1.s2.dmDisplayOrientation);
3303 else
3304 WARN("Failed to query %s display settings.\n", wine_dbgstr_w(lpszDeviceName));
3305 return ret;
3309 /**********************************************************************
3310 * get_monitor_dpi
3312 UINT get_monitor_dpi( HMONITOR monitor )
3314 /* FIXME: use the monitor DPI instead */
3315 return system_dpi;
3318 /**********************************************************************
3319 * get_win_monitor_dpi
3321 UINT get_win_monitor_dpi( HWND hwnd )
3323 /* FIXME: use the monitor DPI instead */
3324 return system_dpi;
3327 /**********************************************************************
3328 * get_thread_dpi
3330 UINT get_thread_dpi(void)
3332 switch (GetAwarenessFromDpiAwarenessContext( GetThreadDpiAwarenessContext() ))
3334 case DPI_AWARENESS_UNAWARE: return USER_DEFAULT_SCREEN_DPI;
3335 case DPI_AWARENESS_SYSTEM_AWARE: return system_dpi;
3336 default: return 0; /* no scaling */
3340 /**********************************************************************
3341 * map_dpi_point
3343 POINT map_dpi_point( POINT pt, UINT dpi_from, UINT dpi_to )
3345 if (dpi_from && dpi_to && dpi_from != dpi_to)
3347 pt.x = MulDiv( pt.x, dpi_to, dpi_from );
3348 pt.y = MulDiv( pt.y, dpi_to, dpi_from );
3350 return pt;
3353 /**********************************************************************
3354 * point_win_to_phys_dpi
3356 POINT point_win_to_phys_dpi( HWND hwnd, POINT pt )
3358 return map_dpi_point( pt, GetDpiForWindow( hwnd ), get_win_monitor_dpi( hwnd ) );
3361 /**********************************************************************
3362 * point_phys_to_win_dpi
3364 POINT point_phys_to_win_dpi( HWND hwnd, POINT pt )
3366 return map_dpi_point( pt, get_win_monitor_dpi( hwnd ), GetDpiForWindow( hwnd ));
3369 /**********************************************************************
3370 * point_win_to_thread_dpi
3372 POINT point_win_to_thread_dpi( HWND hwnd, POINT pt )
3374 UINT dpi = get_thread_dpi();
3375 if (!dpi) dpi = get_win_monitor_dpi( hwnd );
3376 return map_dpi_point( pt, GetDpiForWindow( hwnd ), dpi );
3379 /**********************************************************************
3380 * point_thread_to_win_dpi
3382 POINT point_thread_to_win_dpi( HWND hwnd, POINT pt )
3384 UINT dpi = get_thread_dpi();
3385 if (!dpi) dpi = get_win_monitor_dpi( hwnd );
3386 return map_dpi_point( pt, dpi, GetDpiForWindow( hwnd ));
3389 /**********************************************************************
3390 * map_dpi_rect
3392 RECT map_dpi_rect( RECT rect, UINT dpi_from, UINT dpi_to )
3394 if (dpi_from && dpi_to && dpi_from != dpi_to)
3396 rect.left = MulDiv( rect.left, dpi_to, dpi_from );
3397 rect.top = MulDiv( rect.top, dpi_to, dpi_from );
3398 rect.right = MulDiv( rect.right, dpi_to, dpi_from );
3399 rect.bottom = MulDiv( rect.bottom, dpi_to, dpi_from );
3401 return rect;
3404 /**********************************************************************
3405 * rect_win_to_thread_dpi
3407 RECT rect_win_to_thread_dpi( HWND hwnd, RECT rect )
3409 UINT dpi = get_thread_dpi();
3410 if (!dpi) dpi = get_win_monitor_dpi( hwnd );
3411 return map_dpi_rect( rect, GetDpiForWindow( hwnd ), dpi );
3414 /**********************************************************************
3415 * rect_thread_to_win_dpi
3417 RECT rect_thread_to_win_dpi( HWND hwnd, RECT rect )
3419 UINT dpi = get_thread_dpi();
3420 if (!dpi) dpi = get_win_monitor_dpi( hwnd );
3421 return map_dpi_rect( rect, dpi, GetDpiForWindow( hwnd ) );
3424 /**********************************************************************
3425 * SetProcessDpiAwarenessContext (USER32.@)
3427 BOOL WINAPI SetProcessDpiAwarenessContext( DPI_AWARENESS_CONTEXT context )
3429 DPI_AWARENESS val = GetAwarenessFromDpiAwarenessContext( context );
3431 if (val == DPI_AWARENESS_INVALID)
3433 SetLastError( ERROR_INVALID_PARAMETER );
3434 return FALSE;
3436 val |= 0x10; /* avoid 0 value */
3437 if (InterlockedCompareExchange( &dpi_awareness, val, 0 ))
3439 SetLastError( ERROR_ACCESS_DENIED );
3440 return FALSE;
3442 TRACE( "set to %p\n", context );
3443 return TRUE;
3446 /**********************************************************************
3447 * GetProcessDpiAwarenessInternal (USER32.@)
3449 BOOL WINAPI GetProcessDpiAwarenessInternal( HANDLE process, DPI_AWARENESS *awareness )
3451 if (process && process != GetCurrentProcess())
3453 WARN( "not supported on other process %p\n", process );
3454 *awareness = DPI_AWARENESS_UNAWARE;
3456 else *awareness = dpi_awareness & 3;
3457 return TRUE;
3460 /**********************************************************************
3461 * SetProcessDpiAwarenessInternal (USER32.@)
3463 BOOL WINAPI SetProcessDpiAwarenessInternal( DPI_AWARENESS awareness )
3465 static const DPI_AWARENESS_CONTEXT contexts[3] = { DPI_AWARENESS_CONTEXT_UNAWARE,
3466 DPI_AWARENESS_CONTEXT_SYSTEM_AWARE,
3467 DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE };
3469 if (awareness < DPI_AWARENESS_UNAWARE || awareness > DPI_AWARENESS_PER_MONITOR_AWARE)
3471 SetLastError( ERROR_INVALID_PARAMETER );
3472 return FALSE;
3474 return SetProcessDpiAwarenessContext( contexts[awareness] );
3477 /***********************************************************************
3478 * AreDpiAwarenessContextsEqual (USER32.@)
3480 BOOL WINAPI AreDpiAwarenessContextsEqual( DPI_AWARENESS_CONTEXT ctx1, DPI_AWARENESS_CONTEXT ctx2 )
3482 DPI_AWARENESS aware1 = GetAwarenessFromDpiAwarenessContext( ctx1 );
3483 DPI_AWARENESS aware2 = GetAwarenessFromDpiAwarenessContext( ctx2 );
3484 return aware1 != DPI_AWARENESS_INVALID && aware1 == aware2;
3487 /***********************************************************************
3488 * GetAwarenessFromDpiAwarenessContext (USER32.@)
3490 DPI_AWARENESS WINAPI GetAwarenessFromDpiAwarenessContext( DPI_AWARENESS_CONTEXT context )
3492 switch ((ULONG_PTR)context)
3494 case 0x10:
3495 case 0x11:
3496 case 0x12:
3497 case 0x80000010:
3498 case 0x80000011:
3499 case 0x80000012:
3500 return (ULONG_PTR)context & 3;
3501 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE:
3502 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE:
3503 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE:
3504 return ~(ULONG_PTR)context;
3505 default:
3506 return DPI_AWARENESS_INVALID;
3510 /***********************************************************************
3511 * IsValidDpiAwarenessContext (USER32.@)
3513 BOOL WINAPI IsValidDpiAwarenessContext( DPI_AWARENESS_CONTEXT context )
3515 return GetAwarenessFromDpiAwarenessContext( context ) != DPI_AWARENESS_INVALID;
3518 /***********************************************************************
3519 * SetProcessDPIAware (USER32.@)
3521 BOOL WINAPI SetProcessDPIAware(void)
3523 TRACE("\n");
3524 InterlockedCompareExchange( &dpi_awareness, 0x11, 0 );
3525 return TRUE;
3528 /***********************************************************************
3529 * IsProcessDPIAware (USER32.@)
3531 BOOL WINAPI IsProcessDPIAware(void)
3533 return GetAwarenessFromDpiAwarenessContext( GetThreadDpiAwarenessContext() ) != DPI_AWARENESS_UNAWARE;
3536 /**********************************************************************
3537 * EnableNonClientDpiScaling (USER32.@)
3539 BOOL WINAPI EnableNonClientDpiScaling( HWND hwnd )
3541 FIXME("(%p): stub\n", hwnd);
3542 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
3543 return FALSE;
3546 /***********************************************************************
3547 * GetDpiForSystem (USER32.@)
3549 UINT WINAPI GetDpiForSystem(void)
3551 if (!IsProcessDPIAware()) return USER_DEFAULT_SCREEN_DPI;
3552 return system_dpi;
3555 /***********************************************************************
3556 * GetDpiForMonitorInternal (USER32.@)
3558 BOOL WINAPI GetDpiForMonitorInternal( HMONITOR monitor, UINT type, UINT *x, UINT *y )
3560 if (type > 2)
3562 SetLastError( ERROR_BAD_ARGUMENTS );
3563 return FALSE;
3565 if (!x || !y)
3567 SetLastError( ERROR_INVALID_ADDRESS );
3568 return FALSE;
3570 switch (GetAwarenessFromDpiAwarenessContext( GetThreadDpiAwarenessContext() ))
3572 case DPI_AWARENESS_UNAWARE: *x = *y = USER_DEFAULT_SCREEN_DPI; break;
3573 case DPI_AWARENESS_SYSTEM_AWARE: *x = *y = system_dpi; break;
3574 default: *x = *y = get_monitor_dpi( monitor ); break;
3576 return TRUE;
3579 /**********************************************************************
3580 * GetThreadDpiAwarenessContext (USER32.@)
3582 DPI_AWARENESS_CONTEXT WINAPI GetThreadDpiAwarenessContext(void)
3584 struct user_thread_info *info = get_user_thread_info();
3586 if (info->dpi_awareness) return ULongToHandle( info->dpi_awareness );
3587 if (dpi_awareness) return ULongToHandle( dpi_awareness );
3588 return ULongToHandle( 0x10 | default_awareness );
3591 /**********************************************************************
3592 * SetThreadDpiAwarenessContext (USER32.@)
3594 DPI_AWARENESS_CONTEXT WINAPI SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT context )
3596 struct user_thread_info *info = get_user_thread_info();
3597 DPI_AWARENESS prev, val = GetAwarenessFromDpiAwarenessContext( context );
3599 if (val == DPI_AWARENESS_INVALID)
3601 SetLastError( ERROR_INVALID_PARAMETER );
3602 return 0;
3604 if (!(prev = info->dpi_awareness))
3606 prev = dpi_awareness;
3607 if (!prev) prev = 0x10 | DPI_AWARENESS_UNAWARE;
3608 prev |= 0x80000000; /* restore to process default */
3610 if (((ULONG_PTR)context & ~(ULONG_PTR)0x13) == 0x80000000) info->dpi_awareness = 0;
3611 else info->dpi_awareness = val | 0x10;
3612 return ULongToHandle( prev );
3615 /**********************************************************************
3616 * LogicalToPhysicalPointForPerMonitorDPI (USER32.@)
3618 BOOL WINAPI LogicalToPhysicalPointForPerMonitorDPI( HWND hwnd, POINT *pt )
3620 RECT rect;
3622 if (!GetWindowRect( hwnd, &rect )) return FALSE;
3623 if (pt->x < rect.left || pt->y < rect.top || pt->x > rect.right || pt->y > rect.bottom) return FALSE;
3624 *pt = point_win_to_phys_dpi( hwnd, *pt );
3625 return TRUE;
3628 /**********************************************************************
3629 * PhysicalToLogicalPointForPerMonitorDPI (USER32.@)
3631 BOOL WINAPI PhysicalToLogicalPointForPerMonitorDPI( HWND hwnd, POINT *pt )
3633 DPI_AWARENESS_CONTEXT context;
3634 RECT rect;
3635 BOOL ret = FALSE;
3637 context = SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
3638 if (GetWindowRect( hwnd, &rect ) &&
3639 pt->x >= rect.left && pt->y >= rect.top && pt->x <= rect.right && pt->y <= rect.bottom)
3641 *pt = point_phys_to_win_dpi( hwnd, *pt );
3642 ret = TRUE;
3644 SetThreadDpiAwarenessContext( context );
3645 return ret;
3648 struct monitor_enum_info
3650 RECT rect;
3651 UINT max_area;
3652 UINT min_distance;
3653 HMONITOR primary;
3654 HMONITOR nearest;
3655 HMONITOR ret;
3658 /* helper callback for MonitorFromRect */
3659 static BOOL CALLBACK monitor_enum( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
3661 struct monitor_enum_info *info = (struct monitor_enum_info *)lp;
3662 RECT intersect;
3664 if (IntersectRect( &intersect, rect, &info->rect ))
3666 /* check for larger intersecting area */
3667 UINT area = (intersect.right - intersect.left) * (intersect.bottom - intersect.top);
3668 if (area > info->max_area)
3670 info->max_area = area;
3671 info->ret = monitor;
3674 else if (!info->max_area) /* if not intersecting, check for min distance */
3676 UINT distance;
3677 UINT x, y;
3679 if (info->rect.right <= rect->left) x = rect->left - info->rect.right;
3680 else if (rect->right <= info->rect.left) x = info->rect.left - rect->right;
3681 else x = 0;
3682 if (info->rect.bottom <= rect->top) y = rect->top - info->rect.bottom;
3683 else if (rect->bottom <= info->rect.top) y = info->rect.top - rect->bottom;
3684 else y = 0;
3685 distance = x * x + y * y;
3686 if (distance < info->min_distance)
3688 info->min_distance = distance;
3689 info->nearest = monitor;
3692 if (!info->primary)
3694 MONITORINFO mon_info;
3695 mon_info.cbSize = sizeof(mon_info);
3696 GetMonitorInfoW( monitor, &mon_info );
3697 if (mon_info.dwFlags & MONITORINFOF_PRIMARY) info->primary = monitor;
3699 return TRUE;
3702 /***********************************************************************
3703 * MonitorFromRect (USER32.@)
3705 HMONITOR WINAPI MonitorFromRect( const RECT *rect, DWORD flags )
3707 struct monitor_enum_info info;
3709 info.rect = *rect;
3710 info.max_area = 0;
3711 info.min_distance = ~0u;
3712 info.primary = 0;
3713 info.nearest = 0;
3714 info.ret = 0;
3716 if (IsRectEmpty(&info.rect))
3718 info.rect.right = info.rect.left + 1;
3719 info.rect.bottom = info.rect.top + 1;
3722 if (!EnumDisplayMonitors( 0, NULL, monitor_enum, (LPARAM)&info )) return 0;
3723 if (!info.ret)
3725 if (flags & MONITOR_DEFAULTTOPRIMARY) info.ret = info.primary;
3726 else if (flags & MONITOR_DEFAULTTONEAREST) info.ret = info.nearest;
3729 TRACE( "%s flags %x returning %p\n", wine_dbgstr_rect(rect), flags, info.ret );
3730 return info.ret;
3733 /***********************************************************************
3734 * MonitorFromPoint (USER32.@)
3736 HMONITOR WINAPI MonitorFromPoint( POINT pt, DWORD flags )
3738 RECT rect;
3740 SetRect( &rect, pt.x, pt.y, pt.x + 1, pt.y + 1 );
3741 return MonitorFromRect( &rect, flags );
3744 /***********************************************************************
3745 * MonitorFromWindow (USER32.@)
3747 HMONITOR WINAPI MonitorFromWindow(HWND hWnd, DWORD dwFlags)
3749 RECT rect;
3750 WINDOWPLACEMENT wp;
3752 TRACE("(%p, 0x%08x)\n", hWnd, dwFlags);
3754 wp.length = sizeof(wp);
3755 if (IsIconic(hWnd) && GetWindowPlacement(hWnd, &wp))
3756 return MonitorFromRect( &wp.rcNormalPosition, dwFlags );
3758 if (GetWindowRect( hWnd, &rect ))
3759 return MonitorFromRect( &rect, dwFlags );
3761 if (!(dwFlags & (MONITOR_DEFAULTTOPRIMARY|MONITOR_DEFAULTTONEAREST))) return 0;
3762 /* retrieve the primary */
3763 SetRect( &rect, 0, 0, 1, 1 );
3764 return MonitorFromRect( &rect, dwFlags );
3767 /* Return FALSE on failure and TRUE on success */
3768 static BOOL update_monitor_cache(void)
3770 SP_DEVINFO_DATA device_data = {sizeof(device_data)};
3771 HDEVINFO devinfo = INVALID_HANDLE_VALUE;
3772 MONITORINFOEXW *monitor_array;
3773 FILETIME filetime = {0};
3774 DWORD device_count = 0;
3775 HANDLE mutex = NULL;
3776 DWORD state_flags;
3777 BOOL ret = FALSE;
3778 BOOL is_replica;
3779 DWORD i = 0, j;
3780 DWORD type;
3782 /* Update monitor cache from SetupAPI if it's outdated */
3783 if (!video_key && RegOpenKeyW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", &video_key ))
3784 return FALSE;
3785 if (RegQueryInfoKeyW( video_key, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &filetime ))
3786 return FALSE;
3787 if (CompareFileTime( &filetime, &last_query_monitors_time ) < 1)
3788 return TRUE;
3790 mutex = get_display_device_init_mutex();
3791 EnterCriticalSection( &monitors_section );
3792 devinfo = SetupDiGetClassDevsW( &GUID_DEVCLASS_MONITOR, L"DISPLAY", NULL, DIGCF_PRESENT );
3794 while (SetupDiEnumDeviceInfo( devinfo, i++, &device_data ))
3796 /* Inactive monitors don't get enumerated */
3797 if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, &type,
3798 (BYTE *)&state_flags, sizeof(DWORD), NULL, 0 ))
3799 goto fail;
3800 if (state_flags & DISPLAY_DEVICE_ACTIVE)
3801 device_count++;
3804 if (device_count && monitor_count < device_count)
3806 monitor_array = heap_alloc( device_count * sizeof(*monitor_array) );
3807 if (!monitor_array)
3808 goto fail;
3809 heap_free( monitors );
3810 monitors = monitor_array;
3813 for (i = 0, monitor_count = 0; SetupDiEnumDeviceInfo( devinfo, i, &device_data ); i++)
3815 if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, &type,
3816 (BYTE *)&state_flags, sizeof(DWORD), NULL, 0 ))
3817 goto fail;
3818 if (!(state_flags & DISPLAY_DEVICE_ACTIVE))
3819 continue;
3820 if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCMONITOR, &type,
3821 (BYTE *)&monitors[monitor_count].rcMonitor, sizeof(RECT), NULL, 0 ))
3822 goto fail;
3824 /* Replicas in mirroring monitor sets don't get enumerated */
3825 is_replica = FALSE;
3826 for (j = 0; j < monitor_count; j++)
3828 if (EqualRect(&monitors[j].rcMonitor, &monitors[monitor_count].rcMonitor))
3830 is_replica = TRUE;
3831 break;
3834 if (is_replica)
3835 continue;
3837 if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCWORK, &type,
3838 (BYTE *)&monitors[monitor_count].rcWork, sizeof(RECT), NULL, 0 ))
3839 goto fail;
3840 if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_ADAPTERNAME, &type,
3841 (BYTE *)monitors[monitor_count].szDevice, CCHDEVICENAME * sizeof(WCHAR), NULL, 0))
3842 goto fail;
3843 monitors[monitor_count].dwFlags =
3844 !wcscmp( L"\\\\.\\DISPLAY1", monitors[monitor_count].szDevice ) ? MONITORINFOF_PRIMARY : 0;
3846 monitor_count++;
3849 last_query_monitors_time = filetime;
3850 ret = TRUE;
3851 fail:
3852 SetupDiDestroyDeviceInfoList( devinfo );
3853 LeaveCriticalSection( &monitors_section );
3854 release_display_device_init_mutex( mutex );
3855 return ret;
3858 BOOL CDECL nulldrv_GetMonitorInfo( HMONITOR handle, MONITORINFO *info )
3860 UINT index = (UINT_PTR)handle - 1;
3862 TRACE("(%p, %p)\n", handle, info);
3864 /* Fallback to report one monitor */
3865 if (handle == NULLDRV_DEFAULT_HMONITOR)
3867 RECT default_rect = {0, 0, 640, 480};
3868 info->rcMonitor = default_rect;
3869 info->rcWork = default_rect;
3870 info->dwFlags = MONITORINFOF_PRIMARY;
3871 if (info->cbSize >= sizeof(MONITORINFOEXW))
3872 lstrcpyW( ((MONITORINFOEXW *)info)->szDevice, L"\\\\.\\DISPLAY1" );
3873 return TRUE;
3876 if (!update_monitor_cache())
3877 return FALSE;
3879 EnterCriticalSection( &monitors_section );
3880 if (index < monitor_count)
3882 info->rcMonitor = monitors[index].rcMonitor;
3883 info->rcWork = monitors[index].rcWork;
3884 info->dwFlags = monitors[index].dwFlags;
3885 if (info->cbSize >= sizeof(MONITORINFOEXW))
3886 lstrcpyW( ((MONITORINFOEXW *)info)->szDevice, monitors[index].szDevice );
3887 LeaveCriticalSection( &monitors_section );
3888 return TRUE;
3890 else
3892 LeaveCriticalSection( &monitors_section );
3893 SetLastError( ERROR_INVALID_MONITOR_HANDLE );
3894 return FALSE;
3898 /***********************************************************************
3899 * GetMonitorInfoA (USER32.@)
3901 BOOL WINAPI GetMonitorInfoA( HMONITOR monitor, LPMONITORINFO info )
3903 MONITORINFOEXW miW;
3904 BOOL ret;
3906 if (info->cbSize == sizeof(MONITORINFO)) return GetMonitorInfoW( monitor, info );
3907 if (info->cbSize != sizeof(MONITORINFOEXA)) return FALSE;
3909 miW.cbSize = sizeof(miW);
3910 ret = GetMonitorInfoW( monitor, (MONITORINFO *)&miW );
3911 if (ret)
3913 MONITORINFOEXA *miA = (MONITORINFOEXA *)info;
3914 miA->rcMonitor = miW.rcMonitor;
3915 miA->rcWork = miW.rcWork;
3916 miA->dwFlags = miW.dwFlags;
3917 WideCharToMultiByte(CP_ACP, 0, miW.szDevice, -1, miA->szDevice, sizeof(miA->szDevice), NULL, NULL);
3919 return ret;
3922 /***********************************************************************
3923 * GetMonitorInfoW (USER32.@)
3925 BOOL WINAPI GetMonitorInfoW( HMONITOR monitor, LPMONITORINFO info )
3927 BOOL ret;
3928 UINT dpi_from, dpi_to;
3930 if (info->cbSize != sizeof(MONITORINFOEXW) && info->cbSize != sizeof(MONITORINFO)) return FALSE;
3932 ret = USER_Driver->pGetMonitorInfo( monitor, info );
3933 if (ret)
3935 if ((dpi_to = get_thread_dpi()))
3937 dpi_from = get_monitor_dpi( monitor );
3938 info->rcMonitor = map_dpi_rect( info->rcMonitor, dpi_from, dpi_to );
3939 info->rcWork = map_dpi_rect( info->rcWork, dpi_from, dpi_to );
3941 TRACE( "flags %04x, monitor %s, work %s\n", info->dwFlags,
3942 wine_dbgstr_rect(&info->rcMonitor), wine_dbgstr_rect(&info->rcWork));
3944 return ret;
3947 struct enum_mon_data
3949 MONITORENUMPROC proc;
3950 LPARAM lparam;
3951 HDC hdc;
3952 POINT origin;
3953 RECT limit;
3956 #ifdef __i386__
3957 /* Some apps pass a non-stdcall callback to EnumDisplayMonitors,
3958 * so we need a small assembly wrapper to call it.
3959 * MJ's Help Diagnostic expects that %ecx contains the address to the rect.
3961 extern BOOL enum_mon_callback_wrapper( HMONITOR monitor, LPRECT rect, struct enum_mon_data *data );
3962 __ASM_GLOBAL_FUNC( enum_mon_callback_wrapper,
3963 "pushl %ebp\n\t"
3964 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
3965 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
3966 "movl %esp,%ebp\n\t"
3967 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
3968 "subl $8,%esp\n\t"
3969 "movl 16(%ebp),%eax\n\t" /* data */
3970 "movl 12(%ebp),%ecx\n\t" /* rect */
3971 "pushl 4(%eax)\n\t" /* data->lparam */
3972 "pushl %ecx\n\t" /* rect */
3973 "pushl 8(%eax)\n\t" /* data->hdc */
3974 "pushl 8(%ebp)\n\t" /* monitor */
3975 "call *(%eax)\n\t" /* data->proc */
3976 "leave\n\t"
3977 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
3978 __ASM_CFI(".cfi_same_value %ebp\n\t")
3979 "ret" )
3980 #endif /* __i386__ */
3982 static BOOL CALLBACK enum_mon_callback( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
3984 struct enum_mon_data *data = (struct enum_mon_data *)lp;
3985 RECT monrect = map_dpi_rect( *rect, get_monitor_dpi( monitor ), get_thread_dpi() );
3987 OffsetRect( &monrect, -data->origin.x, -data->origin.y );
3988 if (!IntersectRect( &monrect, &monrect, &data->limit )) return TRUE;
3989 #ifdef __i386__
3990 return enum_mon_callback_wrapper( monitor, &monrect, data );
3991 #else
3992 return data->proc( monitor, data->hdc, &monrect, data->lparam );
3993 #endif
3996 BOOL CDECL nulldrv_EnumDisplayMonitors( HDC hdc, RECT *rect, MONITORENUMPROC proc, LPARAM lp )
3998 RECT monitor_rect;
3999 DWORD i = 0;
4001 TRACE("(%p, %p, %p, 0x%lx)\n", hdc, rect, proc, lp);
4003 if (update_monitor_cache())
4005 while (TRUE)
4007 EnterCriticalSection( &monitors_section );
4008 if (i >= monitor_count)
4010 LeaveCriticalSection( &monitors_section );
4011 return TRUE;
4013 monitor_rect = monitors[i].rcMonitor;
4014 LeaveCriticalSection( &monitors_section );
4016 if (!proc( (HMONITOR)(UINT_PTR)(i + 1), hdc, &monitor_rect, lp ))
4017 return FALSE;
4019 ++i;
4023 /* Fallback to report one monitor if using SetupAPI failed */
4024 SetRect( &monitor_rect, 0, 0, 640, 480 );
4025 if (!proc( NULLDRV_DEFAULT_HMONITOR, hdc, &monitor_rect, lp ))
4026 return FALSE;
4027 return TRUE;
4030 /***********************************************************************
4031 * EnumDisplayMonitors (USER32.@)
4033 BOOL WINAPI EnumDisplayMonitors( HDC hdc, LPRECT rect, MONITORENUMPROC proc, LPARAM lp )
4035 struct enum_mon_data data;
4037 data.proc = proc;
4038 data.lparam = lp;
4039 data.hdc = hdc;
4041 if (hdc)
4043 if (!GetDCOrgEx( hdc, &data.origin )) return FALSE;
4044 if (GetClipBox( hdc, &data.limit ) == ERROR) return FALSE;
4046 else
4048 data.origin.x = data.origin.y = 0;
4049 data.limit.left = data.limit.top = INT_MIN;
4050 data.limit.right = data.limit.bottom = INT_MAX;
4052 if (rect && !IntersectRect( &data.limit, &data.limit, rect )) return TRUE;
4053 return USER_Driver->pEnumDisplayMonitors( 0, NULL, enum_mon_callback, (LPARAM)&data );
4056 /***********************************************************************
4057 * EnumDisplayDevicesA (USER32.@)
4059 BOOL WINAPI EnumDisplayDevicesA( LPCSTR device, DWORD index, DISPLAY_DEVICEA *info, DWORD flags )
4061 UNICODE_STRING deviceW;
4062 DISPLAY_DEVICEW ddW;
4063 BOOL ret;
4065 if (device)
4066 RtlCreateUnicodeStringFromAsciiz( &deviceW, device );
4067 else
4068 deviceW.Buffer = NULL;
4070 ddW.cb = sizeof(ddW);
4071 ret = EnumDisplayDevicesW( deviceW.Buffer, index, &ddW, flags );
4072 RtlFreeUnicodeString( &deviceW );
4074 if (!ret)
4075 return ret;
4077 WideCharToMultiByte( CP_ACP, 0, ddW.DeviceName, -1, info->DeviceName, sizeof(info->DeviceName), NULL, NULL );
4078 WideCharToMultiByte( CP_ACP, 0, ddW.DeviceString, -1, info->DeviceString, sizeof(info->DeviceString), NULL, NULL );
4079 info->StateFlags = ddW.StateFlags;
4081 if (info->cb >= offsetof(DISPLAY_DEVICEA, DeviceID) + sizeof(info->DeviceID))
4082 WideCharToMultiByte( CP_ACP, 0, ddW.DeviceID, -1, info->DeviceID, sizeof(info->DeviceID), NULL, NULL );
4083 if (info->cb >= offsetof(DISPLAY_DEVICEA, DeviceKey) + sizeof(info->DeviceKey))
4084 WideCharToMultiByte( CP_ACP, 0, ddW.DeviceKey, -1, info->DeviceKey, sizeof(info->DeviceKey), NULL, NULL );
4086 return TRUE;
4089 /***********************************************************************
4090 * EnumDisplayDevicesW (USER32.@)
4092 BOOL WINAPI EnumDisplayDevicesW( LPCWSTR device, DWORD index, DISPLAY_DEVICEW *info, DWORD flags )
4094 SP_DEVINFO_DATA device_data = {sizeof(device_data)};
4095 HDEVINFO set = INVALID_HANDLE_VALUE;
4096 WCHAR key_nameW[MAX_PATH];
4097 WCHAR instanceW[MAX_PATH];
4098 WCHAR bufferW[1024];
4099 LONG adapter_index;
4100 WCHAR *next_charW;
4101 HANDLE mutex;
4102 DWORD size;
4103 DWORD type;
4104 HKEY hkey;
4105 BOOL ret = FALSE;
4107 TRACE("%s %d %p %#x\n", debugstr_w( device ), index, info, flags);
4109 wait_graphics_driver_ready();
4110 mutex = get_display_device_init_mutex();
4112 /* Find adapter */
4113 if (!device)
4115 swprintf( key_nameW, ARRAY_SIZE(key_nameW), L"\\Device\\Video%d", index );
4116 size = sizeof(bufferW);
4117 if (RegGetValueW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", key_nameW, RRF_RT_REG_SZ, NULL, bufferW, &size ))
4118 goto done;
4120 /* DeviceKey */
4121 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(info->DeviceKey))
4122 lstrcpyW( info->DeviceKey, bufferW );
4124 /* DeviceName */
4125 swprintf( info->DeviceName, ARRAY_SIZE(info->DeviceName), L"\\\\.\\DISPLAY%d", index + 1 );
4127 /* Strip \Registry\Machine\ */
4128 lstrcpyW( key_nameW, bufferW + 18 );
4130 /* DeviceString */
4131 size = sizeof(info->DeviceString);
4132 if (RegGetValueW( HKEY_LOCAL_MACHINE, key_nameW, L"DriverDesc", RRF_RT_REG_SZ, NULL,
4133 info->DeviceString, &size ))
4134 goto done;
4136 /* StateFlags */
4137 size = sizeof(info->StateFlags);
4138 if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, L"StateFlags", RRF_RT_REG_DWORD, NULL,
4139 &info->StateFlags, &size ))
4140 goto done;
4142 /* DeviceID */
4143 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->DeviceID))
4145 if (flags & EDD_GET_DEVICE_INTERFACE_NAME)
4146 info->DeviceID[0] = 0;
4147 else
4149 size = sizeof(bufferW);
4150 if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, L"GPUID", RRF_RT_REG_SZ | RRF_ZEROONFAILURE, NULL,
4151 bufferW, &size ))
4152 goto done;
4153 set = SetupDiCreateDeviceInfoList( &GUID_DEVCLASS_DISPLAY, NULL );
4154 if (!SetupDiOpenDeviceInfoW( set, bufferW, NULL, 0, &device_data )
4155 || !SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_HARDWAREID, NULL, (BYTE *)bufferW,
4156 sizeof(bufferW), NULL ))
4157 goto done;
4158 lstrcpyW( info->DeviceID, bufferW );
4162 /* Find monitor */
4163 else
4165 /* Check adapter name */
4166 if (wcsnicmp( device, L"\\\\.\\DISPLAY", lstrlenW(L"\\\\.\\DISPLAY") ))
4167 goto done;
4169 adapter_index = wcstol( device + lstrlenW(L"\\\\.\\DISPLAY"), NULL, 10 );
4170 swprintf( key_nameW, ARRAY_SIZE(key_nameW), L"\\Device\\Video%d", adapter_index - 1 );
4172 size = sizeof(bufferW);
4173 if (RegGetValueW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", key_nameW, RRF_RT_REG_SZ, NULL, bufferW, &size ))
4174 goto done;
4176 /* DeviceName */
4177 swprintf( info->DeviceName, ARRAY_SIZE(info->DeviceName), L"\\\\.\\DISPLAY%d\\Monitor%d", adapter_index, index );
4179 /* Get monitor instance */
4180 /* Strip \Registry\Machine\ first */
4181 lstrcpyW( key_nameW, bufferW + 18 );
4182 swprintf( bufferW, ARRAY_SIZE(bufferW), L"MonitorID%d", index );
4184 size = sizeof(instanceW);
4185 if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, bufferW, RRF_RT_REG_SZ, NULL, instanceW, &size ))
4186 goto done;
4188 set = SetupDiCreateDeviceInfoList( &GUID_DEVCLASS_MONITOR, NULL );
4189 if (!SetupDiOpenDeviceInfoW( set, instanceW, NULL, 0, &device_data ))
4190 goto done;
4192 /* StateFlags */
4193 if (!SetupDiGetDevicePropertyW( set, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, &type,
4194 (BYTE *)&info->StateFlags, sizeof(info->StateFlags), NULL, 0 ))
4195 goto done;
4197 /* DeviceString */
4198 if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_DEVICEDESC, NULL,
4199 (BYTE *)info->DeviceString,
4200 sizeof(info->DeviceString), NULL ))
4201 goto done;
4203 /* DeviceKey */
4204 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(info->DeviceKey))
4206 if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW,
4207 sizeof(bufferW), NULL ))
4208 goto done;
4210 lstrcpyW( info->DeviceKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\" );
4211 lstrcatW( info->DeviceKey, bufferW );
4214 /* DeviceID */
4215 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->DeviceID))
4217 if (flags & EDD_GET_DEVICE_INTERFACE_NAME)
4219 lstrcpyW( info->DeviceID, L"\\\\\?\\" );
4220 lstrcatW( info->DeviceID, instanceW );
4221 lstrcatW( info->DeviceID, L"#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}" );
4222 /* Replace '\\' with '#' after prefix */
4223 for (next_charW = info->DeviceID + lstrlenW( L"\\\\\?\\" ); *next_charW;
4224 next_charW++)
4226 if (*next_charW == '\\')
4227 *next_charW = '#';
4230 else
4232 if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_HARDWAREID, NULL, (BYTE *)bufferW,
4233 sizeof(bufferW), NULL ))
4234 goto done;
4236 lstrcpyW( info->DeviceID, bufferW );
4237 lstrcatW( info->DeviceID, L"\\" );
4239 if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW,
4240 sizeof(bufferW), NULL ))
4241 goto done;
4243 lstrcatW( info->DeviceID, bufferW );
4248 ret = TRUE;
4249 done:
4250 release_display_device_init_mutex( mutex );
4251 SetupDiDestroyDeviceInfoList( set );
4252 if (ret)
4253 return ret;
4255 /* Fallback to report at least one adapter and monitor, if user driver didn't initialize display device registry */
4256 if (index)
4257 return FALSE;
4259 /* If user driver did initialize the registry, then exit */
4260 if (!RegOpenKeyW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", &hkey ))
4262 RegCloseKey( hkey );
4263 return FALSE;
4265 WARN("Reporting fallback display devices\n");
4267 /* Adapter */
4268 if (!device)
4270 lstrcpyW( info->DeviceName, L"\\\\.\\DISPLAY1" );
4271 lstrcpyW( info->DeviceString, L"Wine Adapter" );
4272 info->StateFlags =
4273 DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_PRIMARY_DEVICE | DISPLAY_DEVICE_VGA_COMPATIBLE;
4274 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->DeviceID))
4276 if (flags & EDD_GET_DEVICE_INTERFACE_NAME)
4277 info->DeviceID[0] = 0;
4278 else
4279 lstrcpyW( info->DeviceID, L"PCI\\VEN_0000&DEV_0000&SUBSYS_00000000&REV_00" );
4282 /* Monitor */
4283 else
4285 if (lstrcmpiW( L"\\\\.\\DISPLAY1", device ))
4286 return FALSE;
4288 lstrcpyW( info->DeviceName, L"\\\\.\\DISPLAY1\\Monitor0" );
4289 lstrcpyW( info->DeviceString, L"Generic Non-PnP Monitor" );
4290 info->StateFlags = DISPLAY_DEVICE_ACTIVE | DISPLAY_DEVICE_ATTACHED;
4291 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->DeviceID))
4293 if (flags & EDD_GET_DEVICE_INTERFACE_NAME)
4294 lstrcpyW( info->DeviceID, L"\\\\\?\\DISPLAY#Default_Monitor#4&17f0ff54&0&UID0#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}" );
4295 else
4296 lstrcpyW( info->DeviceID, L"MONITOR\\Default_Monitor\\{4d36e96e-e325-11ce-bfc1-08002be10318}\\0000" );
4300 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(info->DeviceKey))
4301 info->DeviceKey[0] = 0;
4303 return TRUE;
4306 /**********************************************************************
4307 * GetAutoRotationState [USER32.@]
4309 BOOL WINAPI GetAutoRotationState( AR_STATE *state )
4311 TRACE("(%p)\n", state);
4313 if (!state)
4315 SetLastError(ERROR_INVALID_PARAMETER);
4316 return FALSE;
4319 *state = AR_NOSENSOR;
4320 return TRUE;
4323 /**********************************************************************
4324 * GetDisplayAutoRotationPreferences [USER32.@]
4326 BOOL WINAPI GetDisplayAutoRotationPreferences( ORIENTATION_PREFERENCE *orientation )
4328 FIXME("(%p): stub\n", orientation);
4329 *orientation = ORIENTATION_PREFERENCE_NONE;
4330 return TRUE;
4333 /* physical<->logical mapping functions from win8 that are nops in later versions */
4335 /***********************************************************************
4336 * GetPhysicalCursorPos (USER32.@)
4338 BOOL WINAPI GetPhysicalCursorPos( POINT *point )
4340 return GetCursorPos( point );
4343 /***********************************************************************
4344 * SetPhysicalCursorPos (USER32.@)
4346 BOOL WINAPI SetPhysicalCursorPos( INT x, INT y )
4348 return SetCursorPos( x, y );
4351 /***********************************************************************
4352 * LogicalToPhysicalPoint (USER32.@)
4354 BOOL WINAPI LogicalToPhysicalPoint( HWND hwnd, POINT *point )
4356 return TRUE;
4359 /***********************************************************************
4360 * PhysicalToLogicalPoint (USER32.@)
4362 BOOL WINAPI PhysicalToLogicalPoint( HWND hwnd, POINT *point )
4364 return TRUE;
4367 /**********************************************************************
4368 * GetDisplayConfigBufferSizes (USER32.@)
4370 LONG WINAPI GetDisplayConfigBufferSizes(UINT32 flags, UINT32 *num_path_info, UINT32 *num_mode_info)
4372 LONG ret = ERROR_GEN_FAILURE;
4373 HANDLE mutex;
4374 HDEVINFO devinfo;
4375 SP_DEVINFO_DATA device_data = {sizeof(device_data)};
4376 DWORD monitor_index = 0, state_flags, type;
4378 FIXME("(0x%x %p %p): semi-stub\n", flags, num_path_info, num_mode_info);
4380 if (!num_path_info || !num_mode_info)
4381 return ERROR_INVALID_PARAMETER;
4383 *num_path_info = 0;
4385 if (flags != QDC_ALL_PATHS &&
4386 flags != QDC_ONLY_ACTIVE_PATHS &&
4387 flags != QDC_DATABASE_CURRENT)
4388 return ERROR_INVALID_PARAMETER;
4390 if (flags != QDC_ONLY_ACTIVE_PATHS)
4391 FIXME("only returning active paths\n");
4393 wait_graphics_driver_ready();
4394 mutex = get_display_device_init_mutex();
4396 /* Iterate through "targets"/monitors.
4397 * Each target corresponds to a path, and each path references a source and a target mode.
4399 devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, L"DISPLAY", NULL, DIGCF_PRESENT);
4400 if (devinfo == INVALID_HANDLE_VALUE)
4401 goto done;
4403 while (SetupDiEnumDeviceInfo(devinfo, monitor_index++, &device_data))
4405 /* Only count active monitors */
4406 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS,
4407 &type, (BYTE *)&state_flags, sizeof(state_flags), NULL, 0))
4408 goto done;
4410 if (state_flags & DISPLAY_DEVICE_ACTIVE)
4411 (*num_path_info)++;
4414 *num_mode_info = *num_path_info * 2;
4415 ret = ERROR_SUCCESS;
4416 TRACE("returning %u path(s) %u mode(s)\n", *num_path_info, *num_mode_info);
4418 done:
4419 SetupDiDestroyDeviceInfoList(devinfo);
4420 release_display_device_init_mutex(mutex);
4421 return ret;
4424 static DISPLAYCONFIG_ROTATION get_dc_rotation(const DEVMODEW *devmode)
4426 if (devmode->dmFields & DM_DISPLAYORIENTATION)
4427 return devmode->u1.s2.dmDisplayOrientation + 1;
4428 else
4429 return DISPLAYCONFIG_ROTATION_IDENTITY;
4432 static DISPLAYCONFIG_SCANLINE_ORDERING get_dc_scanline_ordering(const DEVMODEW *devmode)
4434 if (!(devmode->dmFields & DM_DISPLAYFLAGS))
4435 return DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED;
4436 else if (devmode->u2.dmDisplayFlags & DM_INTERLACED)
4437 return DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED;
4438 else
4439 return DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE;
4442 static DISPLAYCONFIG_PIXELFORMAT get_dc_pixelformat(DWORD dmBitsPerPel)
4444 if ((dmBitsPerPel == 8) || (dmBitsPerPel == 16) ||
4445 (dmBitsPerPel == 24) || (dmBitsPerPel == 32))
4446 return dmBitsPerPel / 8;
4447 else
4448 return DISPLAYCONFIG_PIXELFORMAT_NONGDI;
4451 static void set_mode_target_info(DISPLAYCONFIG_MODE_INFO *info, const LUID *gpu_luid, UINT32 target_id,
4452 UINT32 flags, const DEVMODEW *devmode)
4454 DISPLAYCONFIG_TARGET_MODE *mode = &(info->u.targetMode);
4456 info->infoType = DISPLAYCONFIG_MODE_INFO_TYPE_TARGET;
4457 info->adapterId = *gpu_luid;
4458 info->id = target_id;
4460 /* FIXME: Populate pixelRate/hSyncFreq/totalSize with real data */
4461 mode->targetVideoSignalInfo.pixelRate = devmode->dmDisplayFrequency * devmode->dmPelsWidth * devmode->dmPelsHeight;
4462 mode->targetVideoSignalInfo.hSyncFreq.Numerator = devmode->dmDisplayFrequency * devmode->dmPelsWidth;
4463 mode->targetVideoSignalInfo.hSyncFreq.Denominator = 1;
4464 mode->targetVideoSignalInfo.vSyncFreq.Numerator = devmode->dmDisplayFrequency;
4465 mode->targetVideoSignalInfo.vSyncFreq.Denominator = 1;
4466 mode->targetVideoSignalInfo.activeSize.cx = devmode->dmPelsWidth;
4467 mode->targetVideoSignalInfo.activeSize.cy = devmode->dmPelsHeight;
4468 if (flags & QDC_DATABASE_CURRENT)
4470 mode->targetVideoSignalInfo.totalSize.cx = 0;
4471 mode->targetVideoSignalInfo.totalSize.cy = 0;
4473 else
4475 mode->targetVideoSignalInfo.totalSize.cx = devmode->dmPelsWidth;
4476 mode->targetVideoSignalInfo.totalSize.cy = devmode->dmPelsHeight;
4478 mode->targetVideoSignalInfo.u.videoStandard = D3DKMDT_VSS_OTHER;
4479 mode->targetVideoSignalInfo.scanLineOrdering = get_dc_scanline_ordering(devmode);
4482 static void set_path_target_info(DISPLAYCONFIG_PATH_TARGET_INFO *info, const LUID *gpu_luid,
4483 UINT32 target_id, UINT32 mode_index, const DEVMODEW *devmode)
4485 info->adapterId = *gpu_luid;
4486 info->id = target_id;
4487 info->u.modeInfoIdx = mode_index;
4488 info->outputTechnology = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL;
4489 info->rotation = get_dc_rotation(devmode);
4490 info->scaling = DISPLAYCONFIG_SCALING_IDENTITY;
4491 info->refreshRate.Numerator = devmode->dmDisplayFrequency;
4492 info->refreshRate.Denominator = 1;
4493 info->scanLineOrdering = get_dc_scanline_ordering(devmode);
4494 info->targetAvailable = TRUE;
4495 info->statusFlags = DISPLAYCONFIG_TARGET_IN_USE;
4498 static void set_mode_source_info(DISPLAYCONFIG_MODE_INFO *info, const LUID *gpu_luid,
4499 UINT32 source_id, const DEVMODEW *devmode)
4501 DISPLAYCONFIG_SOURCE_MODE *mode = &(info->u.sourceMode);
4503 info->infoType = DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE;
4504 info->adapterId = *gpu_luid;
4505 info->id = source_id;
4507 mode->width = devmode->dmPelsWidth;
4508 mode->height = devmode->dmPelsHeight;
4509 mode->pixelFormat = get_dc_pixelformat(devmode->dmBitsPerPel);
4510 if (devmode->dmFields & DM_POSITION)
4512 mode->position = devmode->u1.s2.dmPosition;
4514 else
4516 mode->position.x = 0;
4517 mode->position.y = 0;
4521 static void set_path_source_info(DISPLAYCONFIG_PATH_SOURCE_INFO *info, const LUID *gpu_luid,
4522 UINT32 source_id, UINT32 mode_index)
4524 info->adapterId = *gpu_luid;
4525 info->id = source_id;
4526 info->u.modeInfoIdx = mode_index;
4527 info->statusFlags = DISPLAYCONFIG_SOURCE_IN_USE;
4530 static BOOL source_mode_exists(const DISPLAYCONFIG_MODE_INFO *modeinfo, UINT32 num_modes,
4531 UINT32 source_id, UINT32 *found_mode_index)
4533 UINT32 i;
4535 for (i = 0; i < num_modes; i++)
4537 if (modeinfo[i].infoType == DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE &&
4538 modeinfo[i].id == source_id)
4540 *found_mode_index = i;
4541 return TRUE;
4544 return FALSE;
4547 /***********************************************************************
4548 * QueryDisplayConfig (USER32.@)
4550 LONG WINAPI QueryDisplayConfig(UINT32 flags, UINT32 *numpathelements, DISPLAYCONFIG_PATH_INFO *pathinfo,
4551 UINT32 *numinfoelements, DISPLAYCONFIG_MODE_INFO *modeinfo,
4552 DISPLAYCONFIG_TOPOLOGY_ID *topologyid)
4554 LONG adapter_index, ret;
4555 HANDLE mutex;
4556 HDEVINFO devinfo;
4557 SP_DEVINFO_DATA device_data = {sizeof(device_data)};
4558 DWORD monitor_index = 0, state_flags, type;
4559 UINT32 output_id, source_mode_index, path_index = 0, mode_index = 0;
4560 LUID gpu_luid;
4561 WCHAR device_name[CCHDEVICENAME];
4562 DEVMODEW devmode;
4564 FIXME("(%08x %p %p %p %p %p): semi-stub\n", flags, numpathelements, pathinfo, numinfoelements, modeinfo, topologyid);
4566 if (!numpathelements || !numinfoelements)
4567 return ERROR_INVALID_PARAMETER;
4569 if (!*numpathelements || !*numinfoelements)
4570 return ERROR_INVALID_PARAMETER;
4572 if (flags != QDC_ALL_PATHS &&
4573 flags != QDC_ONLY_ACTIVE_PATHS &&
4574 flags != QDC_DATABASE_CURRENT)
4575 return ERROR_INVALID_PARAMETER;
4577 if (((flags == QDC_DATABASE_CURRENT) && !topologyid) ||
4578 ((flags != QDC_DATABASE_CURRENT) && topologyid))
4579 return ERROR_INVALID_PARAMETER;
4581 if (flags != QDC_ONLY_ACTIVE_PATHS)
4582 FIXME("only returning active paths\n");
4584 if (topologyid)
4586 FIXME("setting toplogyid to DISPLAYCONFIG_TOPOLOGY_INTERNAL\n");
4587 *topologyid = DISPLAYCONFIG_TOPOLOGY_INTERNAL;
4590 wait_graphics_driver_ready();
4591 mutex = get_display_device_init_mutex();
4593 /* Iterate through "targets"/monitors.
4594 * Each target corresponds to a path, and each path corresponds to one or two unique modes.
4596 devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, L"DISPLAY", NULL, DIGCF_PRESENT);
4597 if (devinfo == INVALID_HANDLE_VALUE)
4599 ret = ERROR_GEN_FAILURE;
4600 goto done;
4603 ret = ERROR_GEN_FAILURE;
4604 while (SetupDiEnumDeviceInfo(devinfo, monitor_index++, &device_data))
4606 /* Only count active monitors */
4607 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS,
4608 &type, (BYTE *)&state_flags, sizeof(state_flags), NULL, 0))
4609 goto done;
4610 if (!(state_flags & DISPLAY_DEVICE_ACTIVE))
4611 continue;
4613 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPROPKEY_MONITOR_GPU_LUID,
4614 &type, (BYTE *)&gpu_luid, sizeof(gpu_luid), NULL, 0))
4615 goto done;
4617 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPROPKEY_MONITOR_OUTPUT_ID,
4618 &type, (BYTE *)&output_id, sizeof(output_id), NULL, 0))
4619 goto done;
4621 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_ADAPTERNAME,
4622 &type, (BYTE *)device_name, sizeof(device_name), NULL, 0))
4623 goto done;
4625 memset(&devmode, 0, sizeof(devmode));
4626 devmode.dmSize = sizeof(devmode);
4627 if (!EnumDisplaySettingsW(device_name, ENUM_CURRENT_SETTINGS, &devmode))
4628 goto done;
4630 /* Extract the adapter index from device_name to use as the source ID */
4631 adapter_index = wcstol(device_name + lstrlenW(L"\\\\.\\DISPLAY"), NULL, 10);
4632 adapter_index--;
4634 if (path_index == *numpathelements || mode_index == *numinfoelements)
4636 ret = ERROR_INSUFFICIENT_BUFFER;
4637 goto done;
4640 pathinfo[path_index].flags = DISPLAYCONFIG_PATH_ACTIVE;
4641 set_mode_target_info(&modeinfo[mode_index], &gpu_luid, output_id, flags, &devmode);
4642 set_path_target_info(&(pathinfo[path_index].targetInfo), &gpu_luid, output_id, mode_index, &devmode);
4644 mode_index++;
4645 if (mode_index == *numinfoelements)
4647 ret = ERROR_INSUFFICIENT_BUFFER;
4648 goto done;
4651 /* Multiple targets can be driven by the same source, ensure a mode
4652 * hasn't already been added for this source.
4654 if (!source_mode_exists(modeinfo, mode_index, adapter_index, &source_mode_index))
4656 set_mode_source_info(&modeinfo[mode_index], &gpu_luid, adapter_index, &devmode);
4657 source_mode_index = mode_index;
4658 mode_index++;
4660 set_path_source_info(&(pathinfo[path_index].sourceInfo), &gpu_luid, adapter_index, source_mode_index);
4661 path_index++;
4664 *numpathelements = path_index;
4665 *numinfoelements = mode_index;
4666 ret = ERROR_SUCCESS;
4668 done:
4669 SetupDiDestroyDeviceInfoList(devinfo);
4670 release_display_device_init_mutex(mutex);
4671 return ret;
4674 /***********************************************************************
4675 * DisplayConfigGetDeviceInfo (USER32.@)
4677 LONG WINAPI DisplayConfigGetDeviceInfo(DISPLAYCONFIG_DEVICE_INFO_HEADER *packet)
4679 LONG ret = ERROR_GEN_FAILURE;
4680 HANDLE mutex;
4681 HDEVINFO devinfo;
4682 SP_DEVINFO_DATA device_data = {sizeof(device_data)};
4683 DWORD index = 0, type;
4684 LUID gpu_luid;
4686 TRACE("(%p)\n", packet);
4688 if (!packet || packet->size < sizeof(*packet))
4689 return ERROR_GEN_FAILURE;
4690 wait_graphics_driver_ready();
4692 switch (packet->type)
4694 case DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME:
4696 DISPLAYCONFIG_SOURCE_DEVICE_NAME *source_name = (DISPLAYCONFIG_SOURCE_DEVICE_NAME *)packet;
4697 WCHAR device_name[CCHDEVICENAME];
4698 LONG source_id;
4700 TRACE("DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME\n");
4702 if (packet->size < sizeof(*source_name))
4703 return ERROR_INVALID_PARAMETER;
4705 mutex = get_display_device_init_mutex();
4706 devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, L"DISPLAY", NULL, DIGCF_PRESENT);
4707 if (devinfo == INVALID_HANDLE_VALUE)
4709 release_display_device_init_mutex(mutex);
4710 return ret;
4713 while (SetupDiEnumDeviceInfo(devinfo, index++, &device_data))
4715 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPROPKEY_MONITOR_GPU_LUID,
4716 &type, (BYTE *)&gpu_luid, sizeof(gpu_luid), NULL, 0))
4717 continue;
4719 if ((source_name->header.adapterId.LowPart != gpu_luid.LowPart) ||
4720 (source_name->header.adapterId.HighPart != gpu_luid.HighPart))
4721 continue;
4723 /* QueryDisplayConfig() derives the source ID from the adapter name. */
4724 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_ADAPTERNAME,
4725 &type, (BYTE *)device_name, sizeof(device_name), NULL, 0))
4726 continue;
4728 source_id = wcstol(device_name + lstrlenW(L"\\\\.\\DISPLAY"), NULL, 10);
4729 source_id--;
4730 if (source_name->header.id != source_id)
4731 continue;
4733 lstrcpyW(source_name->viewGdiDeviceName, device_name);
4734 ret = ERROR_SUCCESS;
4735 break;
4737 SetupDiDestroyDeviceInfoList(devinfo);
4738 release_display_device_init_mutex(mutex);
4739 return ret;
4741 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME:
4743 DISPLAYCONFIG_TARGET_DEVICE_NAME *target_name = (DISPLAYCONFIG_TARGET_DEVICE_NAME *)packet;
4745 FIXME("DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME: stub\n");
4747 if (packet->size < sizeof(*target_name))
4748 return ERROR_INVALID_PARAMETER;
4750 return ERROR_NOT_SUPPORTED;
4752 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE:
4754 DISPLAYCONFIG_TARGET_PREFERRED_MODE *preferred_mode = (DISPLAYCONFIG_TARGET_PREFERRED_MODE *)packet;
4756 FIXME("DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE: stub\n");
4758 if (packet->size < sizeof(*preferred_mode))
4759 return ERROR_INVALID_PARAMETER;
4761 return ERROR_NOT_SUPPORTED;
4763 case DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME:
4765 DISPLAYCONFIG_ADAPTER_NAME *adapter_name = (DISPLAYCONFIG_ADAPTER_NAME *)packet;
4767 FIXME("DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME: stub\n");
4769 if (packet->size < sizeof(*adapter_name))
4770 return ERROR_INVALID_PARAMETER;
4772 return ERROR_NOT_SUPPORTED;
4774 case DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE:
4775 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE:
4776 case DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION:
4777 case DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION:
4778 case DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO:
4779 case DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE:
4780 case DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL:
4781 default:
4782 FIXME("Unimplemented packet type: %u\n", packet->type);
4783 return ERROR_INVALID_PARAMETER;