wow64: Add thunks for the I/O completion syscalls.
[wine.git] / dlls / user32 / sysparams.c
blob1c94376792780295ed8ba6199d2e33649ed704f8
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 display device information */
111 struct display_device
113 struct list entry; /* Device list entry */
114 struct list children; /* Child device list entry. For adapters, this is monitor list. For monitors, this is unused. */
115 WCHAR device_name[32]; /* as DeviceName in DISPLAY_DEVICEW */
116 WCHAR device_string[128]; /* as DeviceString in DISPLAY_DEVICEW */
117 DWORD state_flags; /* as StateFlags in DISPLAY_DEVICEW */
118 WCHAR device_id[128]; /* as DeviceID in DISPLAY_DEVICEW when EDD_GET_DEVICE_INTERFACE_NAME is not set */
119 WCHAR interface_name[128]; /* as DeviceID in DISPLAY_DEVICEW when EDD_GET_DEVICE_INTERFACE_NAME is set */
120 WCHAR device_key[128]; /* as DeviceKey in DISPLAY_DEVICEW */
123 static struct list adapters = LIST_INIT(adapters);
124 static FILETIME last_query_display_time;
125 static CRITICAL_SECTION display_section;
126 static CRITICAL_SECTION_DEBUG display_critsect_debug =
128 0, 0, &display_section,
129 { &display_critsect_debug.ProcessLocksList, &display_critsect_debug.ProcessLocksList },
130 0, 0, { (DWORD_PTR)(__FILE__ ": display_section") }
132 static CRITICAL_SECTION display_section = { &display_critsect_debug, -1, 0, 0, 0, 0 };
134 static BOOL enum_display_device( WCHAR *device, DWORD index, struct display_device *info );
136 /* Cached monitor information */
137 static MONITORINFOEXW *monitors;
138 static UINT monitor_count;
139 static FILETIME last_query_monitors_time;
140 static CRITICAL_SECTION monitors_section;
141 static CRITICAL_SECTION_DEBUG monitors_critsect_debug =
143 0, 0, &monitors_section,
144 { &monitors_critsect_debug.ProcessLocksList, &monitors_critsect_debug.ProcessLocksList },
145 0, 0, { (DWORD_PTR)(__FILE__ ": monitors_section") }
147 static CRITICAL_SECTION monitors_section = { &monitors_critsect_debug, -1 , 0, 0, 0, 0 };
149 static HDC display_dc;
150 static CRITICAL_SECTION display_dc_section;
151 static CRITICAL_SECTION_DEBUG critsect_debug =
153 0, 0, &display_dc_section,
154 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
155 0, 0, { (DWORD_PTR)(__FILE__ ": display_dc_section") }
157 static CRITICAL_SECTION display_dc_section = { &critsect_debug, -1 ,0, 0, 0, 0 };
160 /* Indicators whether system parameter value is loaded */
161 static char spi_loaded[SPI_INDEX_COUNT];
163 static BOOL notify_change = TRUE;
165 /* System parameters storage */
166 static RECT work_area;
167 static UINT system_dpi;
168 static DPI_AWARENESS dpi_awareness;
169 static DPI_AWARENESS default_awareness = DPI_AWARENESS_UNAWARE;
171 static HKEY volatile_base_key;
172 static HKEY video_key;
174 union sysparam_all_entry;
176 struct sysparam_entry
178 BOOL (*get)( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi );
179 BOOL (*set)( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags );
180 BOOL (*init)( union sysparam_all_entry *entry );
181 enum parameter_key base_key;
182 const WCHAR *regval;
183 enum parameter_key mirror_key;
184 const WCHAR *mirror;
185 BOOL loaded;
188 struct sysparam_uint_entry
190 struct sysparam_entry hdr;
191 UINT val;
194 struct sysparam_bool_entry
196 struct sysparam_entry hdr;
197 BOOL val;
200 struct sysparam_dword_entry
202 struct sysparam_entry hdr;
203 DWORD val;
206 struct sysparam_rgb_entry
208 struct sysparam_entry hdr;
209 COLORREF val;
210 HBRUSH brush;
211 HPEN pen;
214 struct sysparam_binary_entry
216 struct sysparam_entry hdr;
217 void *ptr;
218 size_t size;
221 struct sysparam_path_entry
223 struct sysparam_entry hdr;
224 WCHAR path[MAX_PATH];
227 struct sysparam_font_entry
229 struct sysparam_entry hdr;
230 UINT weight;
231 LOGFONTW val;
232 WCHAR fullname[LF_FACESIZE];
235 struct sysparam_pref_entry
237 struct sysparam_entry hdr;
238 struct sysparam_binary_entry *parent;
239 UINT offset;
240 UINT mask;
243 union sysparam_all_entry
245 struct sysparam_entry hdr;
246 struct sysparam_uint_entry uint;
247 struct sysparam_bool_entry bool;
248 struct sysparam_dword_entry dword;
249 struct sysparam_rgb_entry rgb;
250 struct sysparam_binary_entry bin;
251 struct sysparam_path_entry path;
252 struct sysparam_font_entry font;
253 struct sysparam_pref_entry pref;
256 static void SYSPARAMS_LogFont16To32W( const LOGFONT16 *font16, LPLOGFONTW font32 )
258 font32->lfHeight = font16->lfHeight;
259 font32->lfWidth = font16->lfWidth;
260 font32->lfEscapement = font16->lfEscapement;
261 font32->lfOrientation = font16->lfOrientation;
262 font32->lfWeight = font16->lfWeight;
263 font32->lfItalic = font16->lfItalic;
264 font32->lfUnderline = font16->lfUnderline;
265 font32->lfStrikeOut = font16->lfStrikeOut;
266 font32->lfCharSet = font16->lfCharSet;
267 font32->lfOutPrecision = font16->lfOutPrecision;
268 font32->lfClipPrecision = font16->lfClipPrecision;
269 font32->lfQuality = font16->lfQuality;
270 font32->lfPitchAndFamily = font16->lfPitchAndFamily;
271 MultiByteToWideChar( CP_ACP, 0, font16->lfFaceName, -1, font32->lfFaceName, LF_FACESIZE );
272 font32->lfFaceName[LF_FACESIZE-1] = 0;
275 static void SYSPARAMS_LogFont32WTo32A( const LOGFONTW* font32W, LPLOGFONTA font32A )
277 font32A->lfHeight = font32W->lfHeight;
278 font32A->lfWidth = font32W->lfWidth;
279 font32A->lfEscapement = font32W->lfEscapement;
280 font32A->lfOrientation = font32W->lfOrientation;
281 font32A->lfWeight = font32W->lfWeight;
282 font32A->lfItalic = font32W->lfItalic;
283 font32A->lfUnderline = font32W->lfUnderline;
284 font32A->lfStrikeOut = font32W->lfStrikeOut;
285 font32A->lfCharSet = font32W->lfCharSet;
286 font32A->lfOutPrecision = font32W->lfOutPrecision;
287 font32A->lfClipPrecision = font32W->lfClipPrecision;
288 font32A->lfQuality = font32W->lfQuality;
289 font32A->lfPitchAndFamily = font32W->lfPitchAndFamily;
290 WideCharToMultiByte( CP_ACP, 0, font32W->lfFaceName, -1, font32A->lfFaceName, LF_FACESIZE, NULL, NULL );
291 font32A->lfFaceName[LF_FACESIZE-1] = 0;
294 static void SYSPARAMS_LogFont32ATo32W( const LOGFONTA* font32A, LPLOGFONTW font32W )
296 font32W->lfHeight = font32A->lfHeight;
297 font32W->lfWidth = font32A->lfWidth;
298 font32W->lfEscapement = font32A->lfEscapement;
299 font32W->lfOrientation = font32A->lfOrientation;
300 font32W->lfWeight = font32A->lfWeight;
301 font32W->lfItalic = font32A->lfItalic;
302 font32W->lfUnderline = font32A->lfUnderline;
303 font32W->lfStrikeOut = font32A->lfStrikeOut;
304 font32W->lfCharSet = font32A->lfCharSet;
305 font32W->lfOutPrecision = font32A->lfOutPrecision;
306 font32W->lfClipPrecision = font32A->lfClipPrecision;
307 font32W->lfQuality = font32A->lfQuality;
308 font32W->lfPitchAndFamily = font32A->lfPitchAndFamily;
309 MultiByteToWideChar( CP_ACP, 0, font32A->lfFaceName, -1, font32W->lfFaceName, LF_FACESIZE );
310 font32W->lfFaceName[LF_FACESIZE-1] = 0;
313 static void SYSPARAMS_NonClientMetrics32WTo32A( const NONCLIENTMETRICSW* lpnm32W, LPNONCLIENTMETRICSA lpnm32A )
315 lpnm32A->iBorderWidth = lpnm32W->iBorderWidth;
316 lpnm32A->iScrollWidth = lpnm32W->iScrollWidth;
317 lpnm32A->iScrollHeight = lpnm32W->iScrollHeight;
318 lpnm32A->iCaptionWidth = lpnm32W->iCaptionWidth;
319 lpnm32A->iCaptionHeight = lpnm32W->iCaptionHeight;
320 SYSPARAMS_LogFont32WTo32A( &lpnm32W->lfCaptionFont, &lpnm32A->lfCaptionFont );
321 lpnm32A->iSmCaptionWidth = lpnm32W->iSmCaptionWidth;
322 lpnm32A->iSmCaptionHeight = lpnm32W->iSmCaptionHeight;
323 SYSPARAMS_LogFont32WTo32A( &lpnm32W->lfSmCaptionFont, &lpnm32A->lfSmCaptionFont );
324 lpnm32A->iMenuWidth = lpnm32W->iMenuWidth;
325 lpnm32A->iMenuHeight = lpnm32W->iMenuHeight;
326 SYSPARAMS_LogFont32WTo32A( &lpnm32W->lfMenuFont, &lpnm32A->lfMenuFont );
327 SYSPARAMS_LogFont32WTo32A( &lpnm32W->lfStatusFont, &lpnm32A->lfStatusFont );
328 SYSPARAMS_LogFont32WTo32A( &lpnm32W->lfMessageFont, &lpnm32A->lfMessageFont );
329 if (lpnm32A->cbSize > FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth))
331 if (lpnm32W->cbSize > FIELD_OFFSET(NONCLIENTMETRICSW, iPaddedBorderWidth))
332 lpnm32A->iPaddedBorderWidth = lpnm32W->iPaddedBorderWidth;
333 else
334 lpnm32A->iPaddedBorderWidth = 0;
338 static void SYSPARAMS_NonClientMetrics32ATo32W( const NONCLIENTMETRICSA* lpnm32A, LPNONCLIENTMETRICSW lpnm32W )
340 lpnm32W->iBorderWidth = lpnm32A->iBorderWidth;
341 lpnm32W->iScrollWidth = lpnm32A->iScrollWidth;
342 lpnm32W->iScrollHeight = lpnm32A->iScrollHeight;
343 lpnm32W->iCaptionWidth = lpnm32A->iCaptionWidth;
344 lpnm32W->iCaptionHeight = lpnm32A->iCaptionHeight;
345 SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfCaptionFont, &lpnm32W->lfCaptionFont );
346 lpnm32W->iSmCaptionWidth = lpnm32A->iSmCaptionWidth;
347 lpnm32W->iSmCaptionHeight = lpnm32A->iSmCaptionHeight;
348 SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfSmCaptionFont, &lpnm32W->lfSmCaptionFont );
349 lpnm32W->iMenuWidth = lpnm32A->iMenuWidth;
350 lpnm32W->iMenuHeight = lpnm32A->iMenuHeight;
351 SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfMenuFont, &lpnm32W->lfMenuFont );
352 SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfStatusFont, &lpnm32W->lfStatusFont );
353 SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfMessageFont, &lpnm32W->lfMessageFont );
354 if (lpnm32W->cbSize > FIELD_OFFSET(NONCLIENTMETRICSW, iPaddedBorderWidth))
356 if (lpnm32A->cbSize > FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth))
357 lpnm32W->iPaddedBorderWidth = lpnm32A->iPaddedBorderWidth;
358 else
359 lpnm32W->iPaddedBorderWidth = 0;
364 /* Helper functions to retrieve monitors info */
366 static BOOL CALLBACK get_virtual_screen_proc( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
368 RECT *virtual_rect = (RECT *)lp;
370 UnionRect( virtual_rect, virtual_rect, rect );
371 return TRUE;
374 RECT get_virtual_screen_rect(void)
376 RECT rect = {0};
378 EnumDisplayMonitors( 0, NULL, get_virtual_screen_proc, (LPARAM)&rect );
379 return rect;
382 static BOOL CALLBACK get_primary_monitor_proc( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
384 RECT *primary_rect = (RECT *)lp;
386 if (!rect->top && !rect->left && rect->right && rect->bottom)
388 *primary_rect = *rect;
389 return FALSE;
392 return TRUE;
395 RECT get_primary_monitor_rect(void)
397 RECT rect = {0};
399 EnumDisplayMonitors( 0, NULL, get_primary_monitor_proc, (LPARAM)&rect );
400 return rect;
403 static BOOL CALLBACK get_monitor_count_proc( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
405 INT *count = (INT *)lp;
407 ++(*count);
408 return TRUE;
411 static INT get_monitor_count(void)
413 INT count = 0;
415 EnumDisplayMonitors( 0, NULL, get_monitor_count_proc, (LPARAM)&count );
416 return count;
419 static BOOL get_primary_adapter(WCHAR *name)
421 DISPLAY_DEVICEW dd;
422 DWORD i;
424 dd.cb = sizeof(dd);
425 for (i = 0; EnumDisplayDevicesW(NULL, i, &dd, 0); ++i)
427 if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
429 lstrcpyW(name, dd.DeviceName);
430 return TRUE;
434 return FALSE;
437 static BOOL is_valid_adapter_name(const WCHAR *name)
439 long int adapter_idx;
440 WCHAR *end;
442 if (wcsnicmp(name, L"\\\\.\\DISPLAY", lstrlenW(L"\\\\.\\DISPLAY")))
443 return FALSE;
445 adapter_idx = wcstol(name + lstrlenW(L"\\\\.\\DISPLAY"), &end, 10);
446 if (*end || adapter_idx < 1)
447 return FALSE;
449 return TRUE;
452 /* get text metrics and/or "average" char width of the specified logfont
453 * for the specified dc */
454 static void get_text_metr_size( HDC hdc, LOGFONTW *plf, TEXTMETRICW * ptm, UINT *psz)
456 HFONT hfont, hfontsav;
457 TEXTMETRICW tm;
458 if( !ptm) ptm = &tm;
459 hfont = CreateFontIndirectW( plf);
460 if( !hfont || ( hfontsav = SelectObject( hdc, hfont)) == NULL ) {
461 ptm->tmHeight = -1;
462 if( psz) *psz = 10;
463 if( hfont) DeleteObject( hfont);
464 return;
466 GetTextMetricsW( hdc, ptm);
467 if( psz)
468 if( !(*psz = GdiGetCharDimensions( hdc, ptm, NULL)))
469 *psz = 10;
470 SelectObject( hdc, hfontsav);
471 DeleteObject( hfont);
474 /***********************************************************************
475 * SYSPARAMS_NotifyChange
477 * Sends notification about system parameter update.
479 static void SYSPARAMS_NotifyChange( UINT uiAction, UINT fWinIni )
481 static const WCHAR emptyW[1];
483 if (notify_change)
485 if (fWinIni & SPIF_UPDATEINIFILE)
487 if (fWinIni & (SPIF_SENDWININICHANGE | SPIF_SENDCHANGE))
488 SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE,
489 uiAction, (LPARAM) emptyW,
490 SMTO_ABORTIFHUNG, 2000, NULL );
492 else
494 /* FIXME notify other wine processes with internal message */
499 /* retrieve the cached base keys for a given entry */
500 static BOOL get_base_keys( enum parameter_key index, HKEY *base_key, HKEY *volatile_key )
502 static HKEY base_keys[NB_PARAM_KEYS];
503 static HKEY volatile_keys[NB_PARAM_KEYS];
504 HKEY key;
506 if (!base_keys[index] && base_key)
508 if (RegCreateKeyW( HKEY_CURRENT_USER, parameter_key_names[index], &key )) return FALSE;
509 if (InterlockedCompareExchangePointer( (void **)&base_keys[index], key, 0 ))
510 RegCloseKey( key );
512 if (!volatile_keys[index] && volatile_key)
514 if (RegCreateKeyExW( volatile_base_key, parameter_key_names[index],
515 0, 0, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &key, 0 )) return FALSE;
516 if (InterlockedCompareExchangePointer( (void **)&volatile_keys[index], key, 0 ))
517 RegCloseKey( key );
519 if (base_key) *base_key = base_keys[index];
520 if (volatile_key) *volatile_key = volatile_keys[index];
521 return TRUE;
524 /* load a value to a registry entry */
525 static DWORD load_entry( struct sysparam_entry *entry, void *data, DWORD size )
527 DWORD type, count;
528 HKEY base_key, volatile_key;
530 if (!get_base_keys( entry->base_key, &base_key, &volatile_key )) return FALSE;
532 count = size;
533 if (RegQueryValueExW( volatile_key, entry->regval, NULL, &type, data, &count ))
535 count = size;
536 if (RegQueryValueExW( base_key, entry->regval, NULL, &type, data, &count )) count = 0;
538 /* make sure strings are null-terminated */
539 if (size && count == size && type == REG_SZ) ((WCHAR *)data)[count / sizeof(WCHAR) - 1] = 0;
540 entry->loaded = TRUE;
541 return count;
544 /* save a value to a registry entry */
545 static BOOL save_entry( const struct sysparam_entry *entry, const void *data, DWORD size,
546 DWORD type, UINT flags )
548 HKEY base_key, volatile_key;
550 if (flags & SPIF_UPDATEINIFILE)
552 if (!get_base_keys( entry->base_key, &base_key, &volatile_key )) return FALSE;
553 if (RegSetValueExW( base_key, entry->regval, 0, type, data, size )) return FALSE;
554 RegDeleteValueW( volatile_key, entry->regval );
556 if (entry->mirror && get_base_keys( entry->mirror_key, &base_key, NULL ))
557 RegSetValueExW( base_key, entry->mirror, 0, type, data, size );
559 else
561 if (!get_base_keys( entry->base_key, NULL, &volatile_key )) return FALSE;
562 if (RegSetValueExW( volatile_key, entry->regval, 0, type, data, size )) return FALSE;
564 return TRUE;
567 /* save a string value to a registry entry */
568 static BOOL save_entry_string( const struct sysparam_entry *entry, const WCHAR *str, UINT flags )
570 return save_entry( entry, str, (lstrlenW(str) + 1) * sizeof(WCHAR), REG_SZ, flags );
573 /* initialize an entry in the registry if missing */
574 static BOOL init_entry( struct sysparam_entry *entry, const void *data, DWORD size, DWORD type )
576 HKEY base_key;
578 if (!get_base_keys( entry->base_key, &base_key, NULL )) return FALSE;
579 if (!RegQueryValueExW( base_key, entry->regval, NULL, NULL, NULL, NULL )) return TRUE;
580 if (RegSetValueExW( base_key, entry->regval, 0, type, data, size )) return FALSE;
581 if (entry->mirror && get_base_keys( entry->mirror_key, &base_key, NULL ))
582 RegSetValueExW( base_key, entry->mirror, 0, type, data, size );
583 entry->loaded = TRUE;
584 return TRUE;
587 /* initialize a string value in the registry if missing */
588 static BOOL init_entry_string( struct sysparam_entry *entry, const WCHAR *str )
590 return init_entry( entry, str, (lstrlenW(str) + 1) * sizeof(WCHAR), REG_SZ );
593 HDC get_display_dc(void)
595 EnterCriticalSection( &display_dc_section );
596 if (!display_dc)
598 HDC dc;
600 LeaveCriticalSection( &display_dc_section );
601 dc = CreateDCW( L"DISPLAY", NULL, NULL, NULL );
602 EnterCriticalSection( &display_dc_section );
603 if (display_dc)
604 DeleteDC(dc);
605 else
606 display_dc = dc;
608 return display_dc;
611 void release_display_dc( HDC hdc )
613 LeaveCriticalSection( &display_dc_section );
616 static HANDLE get_display_device_init_mutex( void )
618 HANDLE mutex = CreateMutexW( NULL, FALSE, L"display_device_init" );
620 WaitForSingleObject( mutex, INFINITE );
621 return mutex;
624 static void release_display_device_init_mutex( HANDLE mutex )
626 ReleaseMutex( mutex );
627 CloseHandle( mutex );
630 /* Wait until graphics driver is loaded by explorer */
631 void wait_graphics_driver_ready(void)
633 static BOOL ready = FALSE;
635 if (!ready)
637 SendMessageW( GetDesktopWindow(), WM_NULL, 0, 0 );
638 ready = TRUE;
642 /* map value from system dpi to standard 96 dpi for storing in the registry */
643 static int map_from_system_dpi( int val )
645 return MulDiv( val, USER_DEFAULT_SCREEN_DPI, GetDpiForSystem() );
648 /* map value from 96 dpi to system or custom dpi */
649 static int map_to_dpi( int val, UINT dpi )
651 if (!dpi) dpi = GetDpiForSystem();
652 return MulDiv( val, dpi, USER_DEFAULT_SCREEN_DPI );
655 static INT CALLBACK real_fontname_proc(const LOGFONTW *lf, const TEXTMETRICW *ntm, DWORD type, LPARAM lparam)
657 const ENUMLOGFONTW *elf = (const ENUMLOGFONTW *)lf;
658 WCHAR *fullname = (WCHAR *)lparam;
660 lstrcpynW( fullname, elf->elfFullName, LF_FACESIZE );
661 return 0;
664 static void get_real_fontname( LOGFONTW *lf, WCHAR fullname[LF_FACESIZE] )
666 HDC hdc = get_display_dc();
667 lstrcpyW( fullname, lf->lfFaceName );
668 EnumFontFamiliesExW( hdc, lf, real_fontname_proc, (LPARAM)fullname, 0 );
669 release_display_dc( hdc );
672 /* adjust some of the raw values found in the registry */
673 static void normalize_nonclientmetrics( NONCLIENTMETRICSW *pncm)
675 TEXTMETRICW tm;
676 HDC hdc = get_display_dc();
678 if( pncm->iBorderWidth < 1) pncm->iBorderWidth = 1;
679 if( pncm->iCaptionWidth < 8) pncm->iCaptionWidth = 8;
680 if( pncm->iScrollWidth < 8) pncm->iScrollWidth = 8;
681 if( pncm->iScrollHeight < 8) pncm->iScrollHeight = 8;
683 /* adjust some heights to the corresponding font */
684 get_text_metr_size( hdc, &pncm->lfMenuFont, &tm, NULL);
685 pncm->iMenuHeight = max( pncm->iMenuHeight, 2 + tm.tmHeight + tm.tmExternalLeading );
686 get_text_metr_size( hdc, &pncm->lfCaptionFont, &tm, NULL);
687 pncm->iCaptionHeight = max( pncm->iCaptionHeight, 2 + tm.tmHeight);
688 get_text_metr_size( hdc, &pncm->lfSmCaptionFont, &tm, NULL);
689 pncm->iSmCaptionHeight = max( pncm->iSmCaptionHeight, 2 + tm.tmHeight);
690 release_display_dc( hdc );
693 static BOOL CALLBACK enum_monitors( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
695 MONITORINFO mi;
697 mi.cbSize = sizeof(mi);
698 if (GetMonitorInfoW( monitor, &mi ) && (mi.dwFlags & MONITORINFOF_PRIMARY))
700 LPRECT work = (LPRECT)lp;
701 *work = mi.rcWork;
702 return FALSE;
704 return TRUE;
707 /* load a uint parameter from the registry */
708 static BOOL get_uint_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
710 if (!ptr_param) return FALSE;
712 if (!entry->hdr.loaded)
714 WCHAR buf[32];
716 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->uint.val = wcstol( buf, NULL, 10 );
718 *(UINT *)ptr_param = entry->uint.val;
719 return TRUE;
722 /* set a uint parameter in the registry */
723 static BOOL set_uint_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
725 WCHAR buf[32];
727 wsprintfW( buf, L"%u", int_param );
728 if (!save_entry_string( &entry->hdr, buf, flags )) return FALSE;
729 entry->uint.val = int_param;
730 entry->hdr.loaded = TRUE;
731 return TRUE;
734 /* initialize a uint parameter */
735 static BOOL init_uint_entry( union sysparam_all_entry *entry )
737 WCHAR buf[32];
739 wsprintfW( buf, L"%u", entry->uint.val );
740 return init_entry_string( &entry->hdr, buf );
743 /* set an int parameter in the registry */
744 static BOOL set_int_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
746 WCHAR buf[32];
748 wsprintfW( buf, L"%d", int_param );
749 if (!save_entry_string( &entry->hdr, buf, flags )) return FALSE;
750 entry->uint.val = int_param;
751 entry->hdr.loaded = TRUE;
752 return TRUE;
755 /* initialize an int parameter */
756 static BOOL init_int_entry( union sysparam_all_entry *entry )
758 WCHAR buf[32];
760 wsprintfW( buf, L"%d", entry->uint.val );
761 return init_entry_string( &entry->hdr, buf );
764 /* load a twips parameter from the registry */
765 static BOOL get_twips_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
767 int val;
769 if (!ptr_param) return FALSE;
771 if (!entry->hdr.loaded)
773 WCHAR buf[32];
775 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->uint.val = wcstol( buf, NULL, 10 );
778 /* Dimensions are quoted as being "twips" values if negative and pixels if positive.
779 * One inch is 1440 twips.
780 * See for example
781 * Technical Reference to the Windows 2000 Registry ->
782 * HKEY_CURRENT_USER -> Control Panel -> Desktop -> WindowMetrics
784 val = entry->uint.val;
785 if (val < 0)
786 val = MulDiv( -val, dpi, 1440 );
787 else
788 val = map_to_dpi( val, dpi );
790 *(int *)ptr_param = val;
791 return TRUE;
794 /* set a twips parameter in the registry */
795 static BOOL set_twips_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
797 int val = int_param;
798 if (val > 0) val = map_from_system_dpi( val );
799 return set_int_entry( entry, val, ptr_param, flags );
802 /* load a bool parameter from the registry */
803 static BOOL get_bool_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
805 if (!ptr_param) return FALSE;
807 if (!entry->hdr.loaded)
809 WCHAR buf[32];
811 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->bool.val = wcstol( buf, NULL, 10 ) != 0;
813 *(UINT *)ptr_param = entry->bool.val;
814 return TRUE;
817 /* set a bool parameter in the registry */
818 static BOOL set_bool_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
820 WCHAR buf[32];
822 wsprintfW( buf, L"%u", int_param != 0 );
823 if (!save_entry_string( &entry->hdr, buf, flags )) return FALSE;
824 entry->bool.val = int_param != 0;
825 entry->hdr.loaded = TRUE;
826 return TRUE;
829 /* initialize a bool parameter */
830 static BOOL init_bool_entry( union sysparam_all_entry *entry )
832 WCHAR buf[32];
834 wsprintfW( buf, L"%u", entry->bool.val != 0 );
835 return init_entry_string( &entry->hdr, buf );
838 /* load a bool parameter using Yes/No strings from the registry */
839 static BOOL get_yesno_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
841 if (!ptr_param) return FALSE;
843 if (!entry->hdr.loaded)
845 WCHAR buf[32];
847 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->bool.val = !lstrcmpiW( L"Yes", buf );
849 *(UINT *)ptr_param = entry->bool.val;
850 return TRUE;
853 /* set a bool parameter using Yes/No strings from the registry */
854 static BOOL set_yesno_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
856 const WCHAR *str = int_param ? L"Yes" : L"No";
858 if (!save_entry_string( &entry->hdr, str, flags )) return FALSE;
859 entry->bool.val = int_param != 0;
860 entry->hdr.loaded = TRUE;
861 return TRUE;
864 /* initialize a bool parameter using Yes/No strings */
865 static BOOL init_yesno_entry( union sysparam_all_entry *entry )
867 return init_entry_string( &entry->hdr, entry->bool.val ? L"Yes" : L"No" );
870 /* load a dword (binary) parameter from the registry */
871 static BOOL get_dword_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
873 if (!ptr_param) return FALSE;
875 if (!entry->hdr.loaded)
877 DWORD val;
878 if (load_entry( &entry->hdr, &val, sizeof(val) ) == sizeof(DWORD)) entry->dword.val = val;
880 *(DWORD *)ptr_param = entry->dword.val;
881 return TRUE;
884 /* set a dword (binary) parameter in the registry */
885 static BOOL set_dword_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
887 DWORD val = PtrToUlong( ptr_param );
889 if (!save_entry( &entry->hdr, &val, sizeof(val), REG_DWORD, flags )) return FALSE;
890 entry->dword.val = val;
891 entry->hdr.loaded = TRUE;
892 return TRUE;
895 /* initialize a dword parameter */
896 static BOOL init_dword_entry( union sysparam_all_entry *entry )
898 return init_entry( &entry->hdr, &entry->dword.val, sizeof(entry->dword.val), REG_DWORD );
901 /* load an RGB parameter from the registry */
902 static BOOL get_rgb_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
904 if (!ptr_param) return FALSE;
906 if (!entry->hdr.loaded)
908 WCHAR buf[32];
910 if (load_entry( &entry->hdr, buf, sizeof(buf) ))
912 DWORD r, g, b;
913 WCHAR *end, *str = buf;
915 r = wcstoul( str, &end, 10 );
916 if (end == str || !*end) goto done;
917 str = end + 1;
918 g = wcstoul( str, &end, 10 );
919 if (end == str || !*end) goto done;
920 str = end + 1;
921 b = wcstoul( str, &end, 10 );
922 if (end == str) goto done;
923 if (r > 255 || g > 255 || b > 255) goto done;
924 entry->rgb.val = RGB( r, g, b );
927 done:
928 *(COLORREF *)ptr_param = entry->rgb.val;
929 return TRUE;
932 /* set an RGB parameter in the registry */
933 static BOOL set_rgb_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
935 WCHAR buf[32];
936 HBRUSH brush;
937 HPEN pen;
939 wsprintfW( buf, L"%u %u %u", GetRValue(int_param), GetGValue(int_param), GetBValue(int_param) );
940 if (!save_entry_string( &entry->hdr, buf, flags )) return FALSE;
941 entry->rgb.val = int_param;
942 entry->hdr.loaded = TRUE;
943 if ((brush = InterlockedExchangePointer( (void **)&entry->rgb.brush, 0 )))
945 __wine_make_gdi_object_system( brush, FALSE );
946 DeleteObject( brush );
948 if ((pen = InterlockedExchangePointer( (void **)&entry->rgb.pen, 0 )))
950 __wine_make_gdi_object_system( pen, FALSE );
951 DeleteObject( pen );
953 return TRUE;
956 /* initialize an RGB parameter */
957 static BOOL init_rgb_entry( union sysparam_all_entry *entry )
959 WCHAR buf[32];
961 wsprintfW( buf, L"%u %u %u", GetRValue(entry->rgb.val), GetGValue(entry->rgb.val), GetBValue(entry->rgb.val) );
962 return init_entry_string( &entry->hdr, buf );
965 /* load a font (binary) parameter from the registry */
966 static BOOL get_font_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
968 LOGFONTW font;
970 if (!ptr_param) return FALSE;
972 if (!entry->hdr.loaded)
974 switch (load_entry( &entry->hdr, &font, sizeof(font) ))
976 case sizeof(font):
977 if (font.lfHeight > 0) /* positive height value means points ( inch/72 ) */
978 font.lfHeight = -MulDiv( font.lfHeight, USER_DEFAULT_SCREEN_DPI, 72 );
979 entry->font.val = font;
980 break;
981 case sizeof(LOGFONT16): /* win9x-winME format */
982 SYSPARAMS_LogFont16To32W( (LOGFONT16 *)&font, &entry->font.val );
983 if (entry->font.val.lfHeight > 0)
984 entry->font.val.lfHeight = -MulDiv( entry->font.val.lfHeight, USER_DEFAULT_SCREEN_DPI, 72 );
985 break;
986 default:
987 WARN( "Unknown format in key %s value %s\n",
988 debugstr_w( parameter_key_names[entry->hdr.base_key] ),
989 debugstr_w( entry->hdr.regval ));
990 /* fall through */
991 case 0: /* use the default GUI font */
992 GetObjectW( GetStockObject( DEFAULT_GUI_FONT ), sizeof(font), &font );
993 font.lfHeight = map_from_system_dpi( font.lfHeight );
994 font.lfWeight = entry->font.weight;
995 entry->font.val = font;
996 break;
998 get_real_fontname( &entry->font.val, entry->font.fullname );
999 entry->hdr.loaded = TRUE;
1001 font = entry->font.val;
1002 font.lfHeight = map_to_dpi( font.lfHeight, dpi );
1003 lstrcpyW( font.lfFaceName, entry->font.fullname );
1004 *(LOGFONTW *)ptr_param = font;
1005 return TRUE;
1008 /* set a font (binary) parameter in the registry */
1009 static BOOL set_font_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
1011 LOGFONTW font;
1012 WCHAR *ptr;
1014 memcpy( &font, ptr_param, sizeof(font) );
1015 /* zero pad the end of lfFaceName so we don't save uninitialised data */
1016 ptr = wmemchr( font.lfFaceName, 0, LF_FACESIZE );
1017 if (ptr) memset( ptr, 0, (font.lfFaceName + LF_FACESIZE - ptr) * sizeof(WCHAR) );
1018 if (font.lfHeight < 0) font.lfHeight = map_from_system_dpi( font.lfHeight );
1020 if (!save_entry( &entry->hdr, &font, sizeof(font), REG_BINARY, flags )) return FALSE;
1021 entry->font.val = font;
1022 get_real_fontname( &entry->font.val, entry->font.fullname );
1023 entry->hdr.loaded = TRUE;
1024 return TRUE;
1027 /* initialize a font (binary) parameter */
1028 static BOOL init_font_entry( union sysparam_all_entry *entry )
1030 GetObjectW( GetStockObject( DEFAULT_GUI_FONT ), sizeof(entry->font.val), &entry->font.val );
1031 entry->font.val.lfHeight = map_from_system_dpi( entry->font.val.lfHeight );
1032 entry->font.val.lfWeight = entry->font.weight;
1033 get_real_fontname( &entry->font.val, entry->font.fullname );
1034 return init_entry( &entry->hdr, &entry->font.val, sizeof(entry->font.val), REG_BINARY );
1037 /* get a path parameter in the registry */
1038 static BOOL get_path_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
1040 if (!ptr_param) return FALSE;
1042 if (!entry->hdr.loaded)
1044 WCHAR buffer[MAX_PATH];
1046 if (load_entry( &entry->hdr, buffer, sizeof(buffer) ))
1047 lstrcpynW( entry->path.path, buffer, MAX_PATH );
1049 lstrcpynW( ptr_param, entry->path.path, int_param );
1050 return TRUE;
1053 /* set a path parameter in the registry */
1054 static BOOL set_path_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
1056 WCHAR buffer[MAX_PATH];
1057 BOOL ret;
1059 lstrcpynW( buffer, ptr_param, MAX_PATH );
1060 ret = save_entry_string( &entry->hdr, buffer, flags );
1061 if (ret)
1063 lstrcpyW( entry->path.path, buffer );
1064 entry->hdr.loaded = TRUE;
1066 return ret;
1069 /* initialize a path parameter */
1070 static BOOL init_path_entry( union sysparam_all_entry *entry )
1072 return init_entry_string( &entry->hdr, entry->path.path );
1075 /* get a binary parameter in the registry */
1076 static BOOL get_binary_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
1078 if (!ptr_param) return FALSE;
1080 if (!entry->hdr.loaded)
1082 void *buffer = HeapAlloc( GetProcessHeap(), 0, entry->bin.size );
1083 DWORD len = load_entry( &entry->hdr, buffer, entry->bin.size );
1085 if (len)
1087 memcpy( entry->bin.ptr, buffer, entry->bin.size );
1088 memset( (char *)entry->bin.ptr + len, 0, entry->bin.size - len );
1090 HeapFree( GetProcessHeap(), 0, buffer );
1092 memcpy( ptr_param, entry->bin.ptr, min( int_param, entry->bin.size ) );
1093 return TRUE;
1096 /* set a binary parameter in the registry */
1097 static BOOL set_binary_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
1099 BOOL ret;
1100 void *buffer = HeapAlloc( GetProcessHeap(), 0, entry->bin.size );
1102 memcpy( buffer, entry->bin.ptr, entry->bin.size );
1103 memcpy( buffer, ptr_param, min( int_param, entry->bin.size ));
1104 ret = save_entry( &entry->hdr, buffer, entry->bin.size, REG_BINARY, flags );
1105 if (ret)
1107 memcpy( entry->bin.ptr, buffer, entry->bin.size );
1108 entry->hdr.loaded = TRUE;
1110 HeapFree( GetProcessHeap(), 0, buffer );
1111 return ret;
1114 /* initialize a binary parameter */
1115 static BOOL init_binary_entry( union sysparam_all_entry *entry )
1117 return init_entry( &entry->hdr, entry->bin.ptr, entry->bin.size, REG_BINARY );
1120 /* get a user pref parameter in the registry */
1121 static BOOL get_userpref_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
1123 union sysparam_all_entry *parent_entry = (union sysparam_all_entry *)entry->pref.parent;
1124 BYTE prefs[8];
1126 if (!ptr_param) return FALSE;
1128 if (!parent_entry->hdr.get( parent_entry, sizeof(prefs), prefs, dpi )) return FALSE;
1129 *(BOOL *)ptr_param = (prefs[entry->pref.offset] & entry->pref.mask) != 0;
1130 return TRUE;
1133 /* set a user pref parameter in the registry */
1134 static BOOL set_userpref_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
1136 union sysparam_all_entry *parent_entry = (union sysparam_all_entry *)entry->pref.parent;
1137 BYTE prefs[8];
1139 parent_entry->hdr.loaded = FALSE; /* force loading it again */
1140 if (!parent_entry->hdr.get( parent_entry, sizeof(prefs), prefs, GetDpiForSystem() )) return FALSE;
1142 if (PtrToUlong( ptr_param )) prefs[entry->pref.offset] |= entry->pref.mask;
1143 else prefs[entry->pref.offset] &= ~entry->pref.mask;
1145 return parent_entry->hdr.set( parent_entry, sizeof(prefs), prefs, flags );
1148 static BOOL get_entry_dpi( void *ptr, UINT int_param, void *ptr_param, UINT dpi )
1150 union sysparam_all_entry *entry = ptr;
1151 return entry->hdr.get( entry, int_param, ptr_param, dpi );
1154 static BOOL get_entry( void *ptr, UINT int_param, void *ptr_param )
1156 return get_entry_dpi( ptr, int_param, ptr_param, GetDpiForSystem() );
1159 static BOOL set_entry( void *ptr, UINT int_param, void *ptr_param, UINT flags )
1161 union sysparam_all_entry *entry = ptr;
1162 return entry->hdr.set( entry, int_param, ptr_param, flags );
1165 #define UINT_ENTRY(name,val,base,reg) \
1166 struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_uint_entry, init_uint_entry, \
1167 base, reg }, (val) }
1169 #define UINT_ENTRY_MIRROR(name,val,base,reg,mirror_base) \
1170 struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_uint_entry, init_uint_entry, \
1171 base, reg, mirror_base, reg }, (val) }
1173 #define INT_ENTRY(name,val,base,reg) \
1174 struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_int_entry, init_int_entry, \
1175 base, reg }, (val) }
1177 #define BOOL_ENTRY(name,val,base,reg) \
1178 struct sysparam_bool_entry entry_##name = { { get_bool_entry, set_bool_entry, init_bool_entry, \
1179 base, reg }, (val) }
1181 #define BOOL_ENTRY_MIRROR(name,val,base,reg,mirror_base) \
1182 struct sysparam_bool_entry entry_##name = { { get_bool_entry, set_bool_entry, init_bool_entry, \
1183 base, reg, mirror_base, reg }, (val) }
1185 #define YESNO_ENTRY(name,val,base,reg) \
1186 struct sysparam_bool_entry entry_##name = { { get_yesno_entry, set_yesno_entry, init_yesno_entry, \
1187 base, reg }, (val) }
1189 #define TWIPS_ENTRY(name,val,base,reg) \
1190 struct sysparam_uint_entry entry_##name = { { get_twips_entry, set_twips_entry, init_int_entry, \
1191 base, reg }, (val) }
1193 #define DWORD_ENTRY(name,val,base,reg) \
1194 struct sysparam_dword_entry entry_##name = { { get_dword_entry, set_dword_entry, init_dword_entry, \
1195 base, reg }, (val) }
1197 #define BINARY_ENTRY(name,data,base,reg) \
1198 struct sysparam_binary_entry entry_##name = { { get_binary_entry, set_binary_entry, init_binary_entry, \
1199 base, reg }, data, sizeof(data) }
1201 #define PATH_ENTRY(name,base,reg) \
1202 struct sysparam_path_entry entry_##name = { { get_path_entry, set_path_entry, init_path_entry, \
1203 base, reg } }
1205 #define FONT_ENTRY(name,weight,base,reg) \
1206 struct sysparam_font_entry entry_##name = { { get_font_entry, set_font_entry, init_font_entry, \
1207 base, reg }, (weight) }
1209 #define USERPREF_ENTRY(name,offset,mask) \
1210 struct sysparam_pref_entry entry_##name = { { get_userpref_entry, set_userpref_entry }, \
1211 &entry_USERPREFERENCESMASK, (offset), (mask) }
1213 static UINT_ENTRY( DRAGWIDTH, 4, DESKTOP_KEY, L"DragWidth" );
1214 static UINT_ENTRY( DRAGHEIGHT, 4, DESKTOP_KEY, L"DragHeight" );
1215 static UINT_ENTRY( DOUBLECLICKTIME, 500, MOUSE_KEY, L"DoubleClickSpeed" );
1216 static UINT_ENTRY( FONTSMOOTHING, 2, DESKTOP_KEY, L"FontSmoothing" );
1217 static UINT_ENTRY( GRIDGRANULARITY, 0, DESKTOP_KEY, L"GridGranularity" );
1218 static UINT_ENTRY( KEYBOARDDELAY, 1, KEYBOARD_KEY, L"KeyboardDelay" );
1219 static UINT_ENTRY( KEYBOARDSPEED, 31, KEYBOARD_KEY, L"KeyboardSpeed" );
1220 static UINT_ENTRY( MENUSHOWDELAY, 400, DESKTOP_KEY, L"MenuShowDelay" );
1221 static UINT_ENTRY( MINARRANGE, ARW_HIDE, METRICS_KEY, L"MinArrange" );
1222 static UINT_ENTRY( MINHORZGAP, 0, METRICS_KEY, L"MinHorzGap" );
1223 static UINT_ENTRY( MINVERTGAP, 0, METRICS_KEY, L"MinVertGap" );
1224 static UINT_ENTRY( MINWIDTH, 154, METRICS_KEY, L"MinWidth" );
1225 static UINT_ENTRY( MOUSEHOVERHEIGHT, 4, MOUSE_KEY, L"MouseHoverHeight" );
1226 static UINT_ENTRY( MOUSEHOVERTIME, 400, MOUSE_KEY, L"MouseHoverTime" );
1227 static UINT_ENTRY( MOUSEHOVERWIDTH, 4, MOUSE_KEY, L"MouseHoverWidth" );
1228 static UINT_ENTRY( MOUSESPEED, 10, MOUSE_KEY, L"MouseSensitivity" );
1229 static UINT_ENTRY( MOUSETRAILS, 0, MOUSE_KEY, L"MouseTrails" );
1230 static UINT_ENTRY( SCREENSAVETIMEOUT, 300, DESKTOP_KEY, L"ScreenSaveTimeOut" );
1231 static UINT_ENTRY( WHEELSCROLLCHARS, 3, DESKTOP_KEY, L"WheelScrollChars" );
1232 static UINT_ENTRY( WHEELSCROLLLINES, 3, DESKTOP_KEY, L"WheelScrollLines" );
1233 static UINT_ENTRY_MIRROR( DOUBLECLKHEIGHT, 4, MOUSE_KEY, L"DoubleClickHeight", DESKTOP_KEY );
1234 static UINT_ENTRY_MIRROR( DOUBLECLKWIDTH, 4, MOUSE_KEY, L"DoubleClickWidth", DESKTOP_KEY );
1235 static UINT_ENTRY_MIRROR( MENUDROPALIGNMENT, 0, DESKTOP_KEY, L"MenuDropAlignment", VERSION_KEY );
1237 static INT_ENTRY( MOUSETHRESHOLD1, 6, MOUSE_KEY, L"MouseThreshold1" );
1238 static INT_ENTRY( MOUSETHRESHOLD2, 10, MOUSE_KEY, L"MouseThreshold2" );
1239 static INT_ENTRY( MOUSEACCELERATION, 1, MOUSE_KEY, L"MouseSpeed" );
1241 static BOOL_ENTRY( BLOCKSENDINPUTRESETS, FALSE, DESKTOP_KEY, L"BlockSendInputResets" );
1242 static BOOL_ENTRY( DRAGFULLWINDOWS, FALSE, DESKTOP_KEY, L"DragFullWindows" );
1243 static BOOL_ENTRY( KEYBOARDPREF, TRUE, KEYBOARDPREF_KEY, L"On" );
1244 static BOOL_ENTRY( LOWPOWERACTIVE, FALSE, DESKTOP_KEY, L"LowPowerActive" );
1245 static BOOL_ENTRY( MOUSEBUTTONSWAP, FALSE, MOUSE_KEY, L"SwapMouseButtons" );
1246 static BOOL_ENTRY( POWEROFFACTIVE, FALSE, DESKTOP_KEY, L"PowerOffActive" );
1247 static BOOL_ENTRY( SCREENREADER, FALSE, SCREENREADER_KEY, L"On" );
1248 static BOOL_ENTRY( SCREENSAVEACTIVE, TRUE, DESKTOP_KEY, L"ScreenSaveActive" );
1249 static BOOL_ENTRY( SCREENSAVERRUNNING, FALSE, DESKTOP_KEY, L"WINE_ScreenSaverRunning" ); /* FIXME - real value */
1250 static BOOL_ENTRY( SHOWSOUNDS, FALSE, SHOWSOUNDS_KEY, L"On" );
1251 static BOOL_ENTRY( SNAPTODEFBUTTON, FALSE, MOUSE_KEY, L"SnapToDefaultButton" );
1252 static BOOL_ENTRY_MIRROR( ICONTITLEWRAP, TRUE, DESKTOP_KEY, L"IconTitleWrap", METRICS_KEY );
1253 static BOOL_ENTRY( AUDIODESC_ON, FALSE, AUDIODESC_KEY, L"On" );
1255 static YESNO_ENTRY( BEEP, TRUE, SOUND_KEY, L"Beep" );
1257 static TWIPS_ENTRY( BORDER, -15, METRICS_KEY, L"BorderWidth" );
1258 static TWIPS_ENTRY( CAPTIONHEIGHT, -270, METRICS_KEY, L"CaptionHeight" );
1259 static TWIPS_ENTRY( CAPTIONWIDTH, -270, METRICS_KEY, L"CaptionWidth" );
1260 static TWIPS_ENTRY( ICONHORIZONTALSPACING, -1125, METRICS_KEY, L"IconSpacing" );
1261 static TWIPS_ENTRY( ICONVERTICALSPACING, -1125, METRICS_KEY, L"IconVerticalSpacing" );
1262 static TWIPS_ENTRY( MENUHEIGHT, -270, METRICS_KEY, L"MenuHeight" );
1263 static TWIPS_ENTRY( MENUWIDTH, -270, METRICS_KEY, L"MenuWidth" );
1264 static TWIPS_ENTRY( PADDEDBORDERWIDTH, 0, METRICS_KEY, L"PaddedBorderWidth" );
1265 static TWIPS_ENTRY( SCROLLHEIGHT, -240, METRICS_KEY, L"ScrollHeight" );
1266 static TWIPS_ENTRY( SCROLLWIDTH, -240, METRICS_KEY, L"ScrollWidth" );
1267 static TWIPS_ENTRY( SMCAPTIONHEIGHT, -225, METRICS_KEY, L"SmCaptionHeight" );
1268 static TWIPS_ENTRY( SMCAPTIONWIDTH, -225, METRICS_KEY, L"SmCaptionWidth" );
1270 static DWORD_ENTRY( ACTIVEWINDOWTRACKING, 0, MOUSE_KEY, L"ActiveWindowTracking" );
1271 static DWORD_ENTRY( ACTIVEWNDTRKTIMEOUT, 0, DESKTOP_KEY, L"ActiveWndTrackTimeout" );
1272 static DWORD_ENTRY( CARETWIDTH, 1, DESKTOP_KEY, L"CaretWidth" );
1273 static DWORD_ENTRY( DPISCALINGVER, 0, DESKTOP_KEY, L"DpiScalingVer" );
1274 static DWORD_ENTRY( FOCUSBORDERHEIGHT, 1, DESKTOP_KEY, L"FocusBorderHeight" );
1275 static DWORD_ENTRY( FOCUSBORDERWIDTH, 1, DESKTOP_KEY, L"FocusBorderWidth" );
1276 static DWORD_ENTRY( FONTSMOOTHINGCONTRAST, 0, DESKTOP_KEY, L"FontSmoothingGamma" );
1277 static DWORD_ENTRY( FONTSMOOTHINGORIENTATION, FE_FONTSMOOTHINGORIENTATIONRGB, DESKTOP_KEY, L"FontSmoothingOrientation" );
1278 static DWORD_ENTRY( FONTSMOOTHINGTYPE, FE_FONTSMOOTHINGSTANDARD, DESKTOP_KEY, L"FontSmoothingType" );
1279 static DWORD_ENTRY( FOREGROUNDFLASHCOUNT, 3, DESKTOP_KEY, L"ForegroundFlashCount" );
1280 static DWORD_ENTRY( FOREGROUNDLOCKTIMEOUT, 0, DESKTOP_KEY, L"ForegroundLockTimeout" );
1281 static DWORD_ENTRY( LOGPIXELS, 0, DESKTOP_KEY, L"LogPixels" );
1282 static DWORD_ENTRY( MOUSECLICKLOCKTIME, 1200, DESKTOP_KEY, L"ClickLockTime" );
1283 static DWORD_ENTRY( AUDIODESC_LOCALE, 0, AUDIODESC_KEY, L"Locale" );
1285 static PATH_ENTRY( DESKPATTERN, DESKTOP_KEY, L"Pattern" );
1286 static PATH_ENTRY( DESKWALLPAPER, DESKTOP_KEY, L"Wallpaper" );
1288 static BYTE user_prefs[8] = { 0x30, 0x00, 0x00, 0x80, 0x12, 0x00, 0x00, 0x00 };
1289 static BINARY_ENTRY( USERPREFERENCESMASK, user_prefs, DESKTOP_KEY, L"UserPreferencesMask" );
1291 static FONT_ENTRY( CAPTIONLOGFONT, FW_BOLD, METRICS_KEY, L"CaptionFont" );
1292 static FONT_ENTRY( ICONTITLELOGFONT, FW_NORMAL, METRICS_KEY, L"IconFont" );
1293 static FONT_ENTRY( MENULOGFONT, FW_NORMAL, METRICS_KEY, L"MenuFont" );
1294 static FONT_ENTRY( MESSAGELOGFONT, FW_NORMAL, METRICS_KEY, L"MessageFont" );
1295 static FONT_ENTRY( SMCAPTIONLOGFONT, FW_NORMAL, METRICS_KEY, L"SmCaptionFont" );
1296 static FONT_ENTRY( STATUSLOGFONT, FW_NORMAL, METRICS_KEY, L"StatusFont" );
1298 static USERPREF_ENTRY( MENUANIMATION, 0, 0x02 );
1299 static USERPREF_ENTRY( COMBOBOXANIMATION, 0, 0x04 );
1300 static USERPREF_ENTRY( LISTBOXSMOOTHSCROLLING, 0, 0x08 );
1301 static USERPREF_ENTRY( GRADIENTCAPTIONS, 0, 0x10 );
1302 static USERPREF_ENTRY( KEYBOARDCUES, 0, 0x20 );
1303 static USERPREF_ENTRY( ACTIVEWNDTRKZORDER, 0, 0x40 );
1304 static USERPREF_ENTRY( HOTTRACKING, 0, 0x80 );
1305 static USERPREF_ENTRY( MENUFADE, 1, 0x02 );
1306 static USERPREF_ENTRY( SELECTIONFADE, 1, 0x04 );
1307 static USERPREF_ENTRY( TOOLTIPANIMATION, 1, 0x08 );
1308 static USERPREF_ENTRY( TOOLTIPFADE, 1, 0x10 );
1309 static USERPREF_ENTRY( CURSORSHADOW, 1, 0x20 );
1310 static USERPREF_ENTRY( MOUSESONAR, 1, 0x40 );
1311 static USERPREF_ENTRY( MOUSECLICKLOCK, 1, 0x80 );
1312 static USERPREF_ENTRY( MOUSEVANISH, 2, 0x01 );
1313 static USERPREF_ENTRY( FLATMENU, 2, 0x02 );
1314 static USERPREF_ENTRY( DROPSHADOW, 2, 0x04 );
1315 static USERPREF_ENTRY( UIEFFECTS, 3, 0x80 );
1316 static USERPREF_ENTRY( DISABLEOVERLAPPEDCONTENT, 4, 0x01 );
1317 static USERPREF_ENTRY( CLIENTAREAANIMATION, 4, 0x02 );
1318 static USERPREF_ENTRY( CLEARTYPE, 4, 0x10 );
1319 static USERPREF_ENTRY( SPEECHRECOGNITION, 4, 0x20 );
1321 static struct sysparam_rgb_entry system_colors[] =
1323 #define RGB_ENTRY(name,val,reg) { { get_rgb_entry, set_rgb_entry, init_rgb_entry, COLORS_KEY, reg }, (val) }
1324 RGB_ENTRY( COLOR_SCROLLBAR, RGB(212, 208, 200), L"Scrollbar" ),
1325 RGB_ENTRY( COLOR_BACKGROUND, RGB(58, 110, 165), L"Background" ),
1326 RGB_ENTRY( COLOR_ACTIVECAPTION, RGB(10, 36, 106), L"ActiveTitle" ),
1327 RGB_ENTRY( COLOR_INACTIVECAPTION, RGB(128, 128, 128), L"InactiveTitle" ),
1328 RGB_ENTRY( COLOR_MENU, RGB(212, 208, 200), L"Menu" ),
1329 RGB_ENTRY( COLOR_WINDOW, RGB(255, 255, 255), L"Window" ),
1330 RGB_ENTRY( COLOR_WINDOWFRAME, RGB(0, 0, 0), L"WindowFrame" ),
1331 RGB_ENTRY( COLOR_MENUTEXT, RGB(0, 0, 0), L"MenuText" ),
1332 RGB_ENTRY( COLOR_WINDOWTEXT, RGB(0, 0, 0), L"WindowText" ),
1333 RGB_ENTRY( COLOR_CAPTIONTEXT, RGB(255, 255, 255), L"TitleText" ),
1334 RGB_ENTRY( COLOR_ACTIVEBORDER, RGB(212, 208, 200), L"ActiveBorder" ),
1335 RGB_ENTRY( COLOR_INACTIVEBORDER, RGB(212, 208, 200), L"InactiveBorder" ),
1336 RGB_ENTRY( COLOR_APPWORKSPACE, RGB(128, 128, 128), L"AppWorkSpace" ),
1337 RGB_ENTRY( COLOR_HIGHLIGHT, RGB(10, 36, 106), L"Hilight" ),
1338 RGB_ENTRY( COLOR_HIGHLIGHTTEXT, RGB(255, 255, 255), L"HilightText" ),
1339 RGB_ENTRY( COLOR_BTNFACE, RGB(212, 208, 200), L"ButtonFace" ),
1340 RGB_ENTRY( COLOR_BTNSHADOW, RGB(128, 128, 128), L"ButtonShadow" ),
1341 RGB_ENTRY( COLOR_GRAYTEXT, RGB(128, 128, 128), L"GrayText" ),
1342 RGB_ENTRY( COLOR_BTNTEXT, RGB(0, 0, 0), L"ButtonText" ),
1343 RGB_ENTRY( COLOR_INACTIVECAPTIONTEXT, RGB(212, 208, 200), L"InactiveTitleText" ),
1344 RGB_ENTRY( COLOR_BTNHIGHLIGHT, RGB(255, 255, 255), L"ButtonHilight" ),
1345 RGB_ENTRY( COLOR_3DDKSHADOW, RGB(64, 64, 64), L"ButtonDkShadow" ),
1346 RGB_ENTRY( COLOR_3DLIGHT, RGB(212, 208, 200), L"ButtonLight" ),
1347 RGB_ENTRY( COLOR_INFOTEXT, RGB(0, 0, 0), L"InfoText" ),
1348 RGB_ENTRY( COLOR_INFOBK, RGB(255, 255, 225), L"InfoWindow" ),
1349 RGB_ENTRY( COLOR_ALTERNATEBTNFACE, RGB(181, 181, 181), L"ButtonAlternateFace" ),
1350 RGB_ENTRY( COLOR_HOTLIGHT, RGB(0, 0, 200), L"HotTrackingColor" ),
1351 RGB_ENTRY( COLOR_GRADIENTACTIVECAPTION, RGB(166, 202, 240), L"GradientActiveTitle" ),
1352 RGB_ENTRY( COLOR_GRADIENTINACTIVECAPTION, RGB(192, 192, 192), L"GradientInactiveTitle" ),
1353 RGB_ENTRY( COLOR_MENUHILIGHT, RGB(10, 36, 106), L"MenuHilight" ),
1354 RGB_ENTRY( COLOR_MENUBAR, RGB(212, 208, 200), L"MenuBar" )
1355 #undef RGB_ENTRY
1358 /* entries that are initialized by default in the registry */
1359 static union sysparam_all_entry * const default_entries[] =
1361 (union sysparam_all_entry *)&entry_ACTIVEWINDOWTRACKING,
1362 (union sysparam_all_entry *)&entry_ACTIVEWNDTRKTIMEOUT,
1363 (union sysparam_all_entry *)&entry_BEEP,
1364 (union sysparam_all_entry *)&entry_BLOCKSENDINPUTRESETS,
1365 (union sysparam_all_entry *)&entry_BORDER,
1366 (union sysparam_all_entry *)&entry_CAPTIONHEIGHT,
1367 (union sysparam_all_entry *)&entry_CAPTIONWIDTH,
1368 (union sysparam_all_entry *)&entry_CARETWIDTH,
1369 (union sysparam_all_entry *)&entry_DESKWALLPAPER,
1370 (union sysparam_all_entry *)&entry_DOUBLECLICKTIME,
1371 (union sysparam_all_entry *)&entry_DOUBLECLKHEIGHT,
1372 (union sysparam_all_entry *)&entry_DOUBLECLKWIDTH,
1373 (union sysparam_all_entry *)&entry_DRAGFULLWINDOWS,
1374 (union sysparam_all_entry *)&entry_DRAGHEIGHT,
1375 (union sysparam_all_entry *)&entry_DRAGWIDTH,
1376 (union sysparam_all_entry *)&entry_FOCUSBORDERHEIGHT,
1377 (union sysparam_all_entry *)&entry_FOCUSBORDERWIDTH,
1378 (union sysparam_all_entry *)&entry_FONTSMOOTHING,
1379 (union sysparam_all_entry *)&entry_FONTSMOOTHINGCONTRAST,
1380 (union sysparam_all_entry *)&entry_FONTSMOOTHINGORIENTATION,
1381 (union sysparam_all_entry *)&entry_FONTSMOOTHINGTYPE,
1382 (union sysparam_all_entry *)&entry_FOREGROUNDFLASHCOUNT,
1383 (union sysparam_all_entry *)&entry_FOREGROUNDLOCKTIMEOUT,
1384 (union sysparam_all_entry *)&entry_ICONHORIZONTALSPACING,
1385 (union sysparam_all_entry *)&entry_ICONTITLEWRAP,
1386 (union sysparam_all_entry *)&entry_ICONVERTICALSPACING,
1387 (union sysparam_all_entry *)&entry_KEYBOARDDELAY,
1388 (union sysparam_all_entry *)&entry_KEYBOARDPREF,
1389 (union sysparam_all_entry *)&entry_KEYBOARDSPEED,
1390 (union sysparam_all_entry *)&entry_LOWPOWERACTIVE,
1391 (union sysparam_all_entry *)&entry_MENUHEIGHT,
1392 (union sysparam_all_entry *)&entry_MENUSHOWDELAY,
1393 (union sysparam_all_entry *)&entry_MENUWIDTH,
1394 (union sysparam_all_entry *)&entry_MOUSEACCELERATION,
1395 (union sysparam_all_entry *)&entry_MOUSEBUTTONSWAP,
1396 (union sysparam_all_entry *)&entry_MOUSECLICKLOCKTIME,
1397 (union sysparam_all_entry *)&entry_MOUSEHOVERHEIGHT,
1398 (union sysparam_all_entry *)&entry_MOUSEHOVERTIME,
1399 (union sysparam_all_entry *)&entry_MOUSEHOVERWIDTH,
1400 (union sysparam_all_entry *)&entry_MOUSESPEED,
1401 (union sysparam_all_entry *)&entry_MOUSETHRESHOLD1,
1402 (union sysparam_all_entry *)&entry_MOUSETHRESHOLD2,
1403 (union sysparam_all_entry *)&entry_PADDEDBORDERWIDTH,
1404 (union sysparam_all_entry *)&entry_SCREENREADER,
1405 (union sysparam_all_entry *)&entry_SCROLLHEIGHT,
1406 (union sysparam_all_entry *)&entry_SCROLLWIDTH,
1407 (union sysparam_all_entry *)&entry_SHOWSOUNDS,
1408 (union sysparam_all_entry *)&entry_SMCAPTIONHEIGHT,
1409 (union sysparam_all_entry *)&entry_SMCAPTIONWIDTH,
1410 (union sysparam_all_entry *)&entry_SNAPTODEFBUTTON,
1411 (union sysparam_all_entry *)&entry_USERPREFERENCESMASK,
1412 (union sysparam_all_entry *)&entry_WHEELSCROLLCHARS,
1413 (union sysparam_all_entry *)&entry_WHEELSCROLLLINES,
1414 (union sysparam_all_entry *)&entry_AUDIODESC_LOCALE,
1415 (union sysparam_all_entry *)&entry_AUDIODESC_ON,
1418 /***********************************************************************
1419 * SYSPARAMS_Init
1421 void SYSPARAMS_Init(void)
1423 HKEY key;
1424 DWORD i, dispos, dpi_scaling;
1426 /* this one must be non-volatile */
1427 if (RegCreateKeyW( HKEY_CURRENT_USER, L"Software\\Wine", &key ))
1429 ERR("Can't create wine registry branch\n");
1430 return;
1433 /* @@ Wine registry key: HKCU\Software\Wine\Temporary System Parameters */
1434 if (RegCreateKeyExW( key, L"Temporary System Parameters", 0, 0,
1435 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, 0, &volatile_base_key, &dispos ))
1436 ERR("Can't create non-permanent wine registry branch\n");
1438 RegCloseKey( key );
1440 get_dword_entry( (union sysparam_all_entry *)&entry_LOGPIXELS, 0, &system_dpi, 0 );
1441 if (!system_dpi) /* check fallback key */
1443 if (!RegOpenKeyW( HKEY_CURRENT_CONFIG, L"Software\\Fonts", &key ))
1445 DWORD type, size = sizeof(system_dpi);
1446 if (RegQueryValueExW( key, L"LogPixels", NULL, &type, (void *)&system_dpi, &size ) ||
1447 type != REG_DWORD)
1448 system_dpi = 0;
1449 RegCloseKey( key );
1452 if (!system_dpi) system_dpi = USER_DEFAULT_SCREEN_DPI;
1454 /* FIXME: what do the DpiScalingVer flags mean? */
1455 get_dword_entry( (union sysparam_all_entry *)&entry_DPISCALINGVER, 0, &dpi_scaling, 0 );
1456 if (!dpi_scaling)
1458 default_awareness = DPI_AWARENESS_PER_MONITOR_AWARE;
1459 dpi_awareness = 0x10 | default_awareness;
1462 if (volatile_base_key && dispos == REG_CREATED_NEW_KEY) /* first process, initialize entries */
1464 for (i = 0; i < ARRAY_SIZE( default_entries ); i++)
1465 default_entries[i]->hdr.init( default_entries[i] );
1469 static BOOL update_desktop_wallpaper(void)
1471 DWORD pid;
1473 if (GetWindowThreadProcessId( GetDesktopWindow(), &pid ) && pid == GetCurrentProcessId())
1475 WCHAR wallpaper[MAX_PATH], pattern[256];
1477 entry_DESKWALLPAPER.hdr.loaded = entry_DESKPATTERN.hdr.loaded = FALSE;
1478 if (get_entry( &entry_DESKWALLPAPER, MAX_PATH, wallpaper ) &&
1479 get_entry( &entry_DESKPATTERN, 256, pattern ))
1480 update_wallpaper( wallpaper, pattern );
1482 else SendMessageW( GetDesktopWindow(), WM_SETTINGCHANGE, SPI_SETDESKWALLPAPER, 0 );
1483 return TRUE;
1487 /***********************************************************************
1488 * SystemParametersInfoForDpi (USER32.@)
1490 BOOL WINAPI SystemParametersInfoForDpi( UINT action, UINT val, PVOID ptr, UINT winini, UINT dpi )
1492 BOOL ret = FALSE;
1494 switch (action)
1496 case SPI_GETICONTITLELOGFONT:
1497 ret = get_entry_dpi( &entry_ICONTITLELOGFONT, val, ptr, dpi );
1498 break;
1499 case SPI_GETNONCLIENTMETRICS:
1501 NONCLIENTMETRICSW *ncm = ptr;
1503 if (!ncm) break;
1504 ret = get_entry_dpi( &entry_BORDER, 0, &ncm->iBorderWidth, dpi ) &&
1505 get_entry_dpi( &entry_SCROLLWIDTH, 0, &ncm->iScrollWidth, dpi ) &&
1506 get_entry_dpi( &entry_SCROLLHEIGHT, 0, &ncm->iScrollHeight, dpi ) &&
1507 get_entry_dpi( &entry_CAPTIONWIDTH, 0, &ncm->iCaptionWidth, dpi ) &&
1508 get_entry_dpi( &entry_CAPTIONHEIGHT, 0, &ncm->iCaptionHeight, dpi ) &&
1509 get_entry_dpi( &entry_CAPTIONLOGFONT, 0, &ncm->lfCaptionFont, dpi ) &&
1510 get_entry_dpi( &entry_SMCAPTIONWIDTH, 0, &ncm->iSmCaptionWidth, dpi ) &&
1511 get_entry_dpi( &entry_SMCAPTIONHEIGHT, 0, &ncm->iSmCaptionHeight, dpi ) &&
1512 get_entry_dpi( &entry_SMCAPTIONLOGFONT, 0, &ncm->lfSmCaptionFont, dpi ) &&
1513 get_entry_dpi( &entry_MENUWIDTH, 0, &ncm->iMenuWidth, dpi ) &&
1514 get_entry_dpi( &entry_MENUHEIGHT, 0, &ncm->iMenuHeight, dpi ) &&
1515 get_entry_dpi( &entry_MENULOGFONT, 0, &ncm->lfMenuFont, dpi ) &&
1516 get_entry_dpi( &entry_STATUSLOGFONT, 0, &ncm->lfStatusFont, dpi ) &&
1517 get_entry_dpi( &entry_MESSAGELOGFONT, 0, &ncm->lfMessageFont, dpi );
1518 if (ret && ncm->cbSize == sizeof(NONCLIENTMETRICSW))
1519 ret = get_entry_dpi( &entry_PADDEDBORDERWIDTH, 0, &ncm->iPaddedBorderWidth, dpi );
1520 normalize_nonclientmetrics( ncm );
1521 break;
1523 case SPI_GETICONMETRICS:
1525 ICONMETRICSW *im = ptr;
1526 if (im && im->cbSize == sizeof(*im))
1527 ret = get_entry_dpi( &entry_ICONHORIZONTALSPACING, 0, &im->iHorzSpacing, dpi ) &&
1528 get_entry_dpi( &entry_ICONVERTICALSPACING, 0, &im->iVertSpacing, dpi ) &&
1529 get_entry_dpi( &entry_ICONTITLEWRAP, 0, &im->iTitleWrap, dpi ) &&
1530 get_entry_dpi( &entry_ICONTITLELOGFONT, 0, &im->lfFont, dpi );
1531 break;
1533 default:
1534 SetLastError( ERROR_INVALID_PARAMETER );
1535 break;
1537 return ret;
1541 /***********************************************************************
1542 * SystemParametersInfoW (USER32.@)
1544 * Each system parameter has flag which shows whether the parameter
1545 * is loaded or not. Parameters, stored directly in SysParametersInfo are
1546 * loaded from registry only when they are requested and the flag is
1547 * "false", after the loading the flag is set to "true". On interprocess
1548 * notification of the parameter change the corresponding parameter flag is
1549 * set to "false". The parameter value will be reloaded when it is requested
1550 * the next time.
1551 * Parameters, backed by or depend on GetSystemMetrics are processed
1552 * differently. These parameters are always loaded. They are reloaded right
1553 * away on interprocess change notification. We can't do lazy loading because
1554 * we don't want to complicate GetSystemMetrics.
1555 * Parameters, backed by X settings are read from corresponding setting.
1556 * On the parameter change request the setting is changed. Interprocess change
1557 * notifications are ignored.
1558 * When parameter value is updated the changed value is stored in permanent
1559 * registry branch if saving is requested. Otherwise it is stored
1560 * in temporary branch
1562 * Some SPI values can also be stored as Twips values in the registry,
1563 * don't forget the conversion!
1565 BOOL WINAPI SystemParametersInfoW( UINT uiAction, UINT uiParam,
1566 PVOID pvParam, UINT fWinIni )
1568 #define WINE_SPI_FIXME(x) \
1569 case x: \
1571 static BOOL warn = TRUE; \
1572 if (warn) \
1574 warn = FALSE; \
1575 FIXME( "Unimplemented action: %u (%s)\n", x, #x ); \
1578 SetLastError( ERROR_INVALID_SPI_VALUE ); \
1579 ret = FALSE; \
1580 break
1581 #define WINE_SPI_WARN(x) \
1582 case x: \
1583 WARN( "Ignored action: %u (%s)\n", x, #x ); \
1584 ret = TRUE; \
1585 break
1587 BOOL ret = USER_Driver->pSystemParametersInfo( uiAction, uiParam, pvParam, fWinIni );
1588 unsigned spi_idx = 0;
1590 if (!ret) switch (uiAction)
1592 case SPI_GETBEEP:
1593 ret = get_entry( &entry_BEEP, uiParam, pvParam );
1594 break;
1595 case SPI_SETBEEP:
1596 ret = set_entry( &entry_BEEP, uiParam, pvParam, fWinIni );
1597 break;
1598 case SPI_GETMOUSE:
1599 ret = get_entry( &entry_MOUSETHRESHOLD1, uiParam, (INT *)pvParam ) &&
1600 get_entry( &entry_MOUSETHRESHOLD2, uiParam, (INT *)pvParam + 1 ) &&
1601 get_entry( &entry_MOUSEACCELERATION, uiParam, (INT *)pvParam + 2 );
1602 break;
1603 case SPI_SETMOUSE:
1604 ret = set_entry( &entry_MOUSETHRESHOLD1, ((INT *)pvParam)[0], pvParam, fWinIni ) &&
1605 set_entry( &entry_MOUSETHRESHOLD2, ((INT *)pvParam)[1], pvParam, fWinIni ) &&
1606 set_entry( &entry_MOUSEACCELERATION, ((INT *)pvParam)[2], pvParam, fWinIni );
1607 break;
1608 case SPI_GETBORDER:
1609 ret = get_entry( &entry_BORDER, uiParam, pvParam );
1610 if (*(INT*)pvParam < 1) *(INT*)pvParam = 1;
1611 break;
1612 case SPI_SETBORDER:
1613 ret = set_entry( &entry_BORDER, uiParam, pvParam, fWinIni );
1614 break;
1615 case SPI_GETKEYBOARDSPEED:
1616 ret = get_entry( &entry_KEYBOARDSPEED, uiParam, pvParam );
1617 break;
1618 case SPI_SETKEYBOARDSPEED:
1619 if (uiParam > 31) uiParam = 31;
1620 ret = set_entry( &entry_KEYBOARDSPEED, uiParam, pvParam, fWinIni );
1621 break;
1623 /* not implemented in Windows */
1624 WINE_SPI_WARN(SPI_LANGDRIVER); /* 12 */
1626 case SPI_ICONHORIZONTALSPACING:
1627 if (pvParam != NULL)
1628 ret = get_entry( &entry_ICONHORIZONTALSPACING, uiParam, pvParam );
1629 else
1631 int min_val = map_to_dpi( 32, GetDpiForSystem() );
1632 ret = set_entry( &entry_ICONHORIZONTALSPACING, max( min_val, uiParam ), pvParam, fWinIni );
1634 break;
1635 case SPI_GETSCREENSAVETIMEOUT:
1636 ret = get_entry( &entry_SCREENSAVETIMEOUT, uiParam, pvParam );
1637 break;
1638 case SPI_SETSCREENSAVETIMEOUT:
1639 ret = set_entry( &entry_SCREENSAVETIMEOUT, uiParam, pvParam, fWinIni );
1640 break;
1641 case SPI_GETSCREENSAVEACTIVE:
1642 ret = get_entry( &entry_SCREENSAVEACTIVE, uiParam, pvParam );
1643 break;
1644 case SPI_SETSCREENSAVEACTIVE:
1645 ret = set_entry( &entry_SCREENSAVEACTIVE, uiParam, pvParam, fWinIni );
1646 break;
1647 case SPI_GETGRIDGRANULARITY:
1648 ret = get_entry( &entry_GRIDGRANULARITY, uiParam, pvParam );
1649 break;
1650 case SPI_SETGRIDGRANULARITY:
1651 ret = set_entry( &entry_GRIDGRANULARITY, uiParam, pvParam, fWinIni );
1652 break;
1653 case SPI_SETDESKWALLPAPER:
1654 if (!pvParam || set_entry( &entry_DESKWALLPAPER, uiParam, pvParam, fWinIni ))
1655 ret = update_desktop_wallpaper();
1656 break;
1657 case SPI_SETDESKPATTERN:
1658 if (!pvParam || set_entry( &entry_DESKPATTERN, uiParam, pvParam, fWinIni ))
1659 ret = update_desktop_wallpaper();
1660 break;
1661 case SPI_GETKEYBOARDDELAY:
1662 ret = get_entry( &entry_KEYBOARDDELAY, uiParam, pvParam );
1663 break;
1664 case SPI_SETKEYBOARDDELAY:
1665 ret = set_entry( &entry_KEYBOARDDELAY, uiParam, pvParam, fWinIni );
1666 break;
1667 case SPI_ICONVERTICALSPACING:
1668 if (pvParam != NULL)
1669 ret = get_entry( &entry_ICONVERTICALSPACING, uiParam, pvParam );
1670 else
1672 int min_val = map_to_dpi( 32, GetDpiForSystem() );
1673 ret = set_entry( &entry_ICONVERTICALSPACING, max( min_val, uiParam ), pvParam, fWinIni );
1675 break;
1676 case SPI_GETICONTITLEWRAP:
1677 ret = get_entry( &entry_ICONTITLEWRAP, uiParam, pvParam );
1678 break;
1679 case SPI_SETICONTITLEWRAP:
1680 ret = set_entry( &entry_ICONTITLEWRAP, uiParam, pvParam, fWinIni );
1681 break;
1682 case SPI_GETMENUDROPALIGNMENT:
1683 ret = get_entry( &entry_MENUDROPALIGNMENT, uiParam, pvParam );
1684 break;
1685 case SPI_SETMENUDROPALIGNMENT:
1686 ret = set_entry( &entry_MENUDROPALIGNMENT, uiParam, pvParam, fWinIni );
1687 break;
1688 case SPI_SETDOUBLECLKWIDTH:
1689 ret = set_entry( &entry_DOUBLECLKWIDTH, uiParam, pvParam, fWinIni );
1690 break;
1691 case SPI_SETDOUBLECLKHEIGHT:
1692 ret = set_entry( &entry_DOUBLECLKHEIGHT, uiParam, pvParam, fWinIni );
1693 break;
1694 case SPI_GETICONTITLELOGFONT:
1695 ret = get_entry( &entry_ICONTITLELOGFONT, uiParam, pvParam );
1696 break;
1697 case SPI_SETDOUBLECLICKTIME:
1698 ret = set_entry( &entry_DOUBLECLICKTIME, uiParam, pvParam, fWinIni );
1699 break;
1700 case SPI_SETMOUSEBUTTONSWAP:
1701 ret = set_entry( &entry_MOUSEBUTTONSWAP, uiParam, pvParam, fWinIni );
1702 break;
1703 case SPI_SETICONTITLELOGFONT:
1704 ret = set_entry( &entry_ICONTITLELOGFONT, uiParam, pvParam, fWinIni );
1705 break;
1707 case SPI_GETFASTTASKSWITCH: /* 35 */
1708 if (!pvParam) return FALSE;
1709 *(BOOL *)pvParam = TRUE;
1710 ret = TRUE;
1711 break;
1713 case SPI_SETFASTTASKSWITCH: /* 36 */
1714 /* the action is disabled */
1715 ret = FALSE;
1716 break;
1718 case SPI_SETDRAGFULLWINDOWS:
1719 ret = set_entry( &entry_DRAGFULLWINDOWS, uiParam, pvParam, fWinIni );
1720 break;
1721 case SPI_GETDRAGFULLWINDOWS:
1722 ret = get_entry( &entry_DRAGFULLWINDOWS, uiParam, pvParam );
1723 break;
1724 case SPI_GETNONCLIENTMETRICS:
1726 LPNONCLIENTMETRICSW lpnm = pvParam;
1727 int padded_border;
1729 if (!pvParam) return FALSE;
1731 ret = get_entry( &entry_BORDER, 0, &lpnm->iBorderWidth ) &&
1732 get_entry( &entry_PADDEDBORDERWIDTH, 0, &padded_border ) &&
1733 get_entry( &entry_SCROLLWIDTH, 0, &lpnm->iScrollWidth ) &&
1734 get_entry( &entry_SCROLLHEIGHT, 0, &lpnm->iScrollHeight ) &&
1735 get_entry( &entry_CAPTIONWIDTH, 0, &lpnm->iCaptionWidth ) &&
1736 get_entry( &entry_CAPTIONHEIGHT, 0, &lpnm->iCaptionHeight ) &&
1737 get_entry( &entry_CAPTIONLOGFONT, 0, &lpnm->lfCaptionFont ) &&
1738 get_entry( &entry_SMCAPTIONWIDTH, 0, &lpnm->iSmCaptionWidth ) &&
1739 get_entry( &entry_SMCAPTIONHEIGHT, 0, &lpnm->iSmCaptionHeight ) &&
1740 get_entry( &entry_SMCAPTIONLOGFONT, 0, &lpnm->lfSmCaptionFont ) &&
1741 get_entry( &entry_MENUWIDTH, 0, &lpnm->iMenuWidth ) &&
1742 get_entry( &entry_MENUHEIGHT, 0, &lpnm->iMenuHeight ) &&
1743 get_entry( &entry_MENULOGFONT, 0, &lpnm->lfMenuFont ) &&
1744 get_entry( &entry_STATUSLOGFONT, 0, &lpnm->lfStatusFont ) &&
1745 get_entry( &entry_MESSAGELOGFONT, 0, &lpnm->lfMessageFont );
1746 if (ret)
1748 lpnm->iBorderWidth += padded_border;
1749 if (lpnm->cbSize == sizeof(NONCLIENTMETRICSW)) lpnm->iPaddedBorderWidth = 0;
1751 normalize_nonclientmetrics( lpnm );
1752 break;
1754 case SPI_SETNONCLIENTMETRICS:
1756 LPNONCLIENTMETRICSW lpnm = pvParam;
1757 int padded_border;
1759 if (lpnm && (lpnm->cbSize == sizeof(NONCLIENTMETRICSW) ||
1760 lpnm->cbSize == FIELD_OFFSET(NONCLIENTMETRICSW, iPaddedBorderWidth)))
1762 get_entry( &entry_PADDEDBORDERWIDTH, 0, &padded_border );
1764 ret = set_entry( &entry_BORDER, lpnm->iBorderWidth - padded_border, NULL, fWinIni ) &&
1765 set_entry( &entry_SCROLLWIDTH, lpnm->iScrollWidth, NULL, fWinIni ) &&
1766 set_entry( &entry_SCROLLHEIGHT, lpnm->iScrollHeight, NULL, fWinIni ) &&
1767 set_entry( &entry_CAPTIONWIDTH, lpnm->iCaptionWidth, NULL, fWinIni ) &&
1768 set_entry( &entry_CAPTIONHEIGHT, lpnm->iCaptionHeight, NULL, fWinIni ) &&
1769 set_entry( &entry_SMCAPTIONWIDTH, lpnm->iSmCaptionWidth, NULL, fWinIni ) &&
1770 set_entry( &entry_SMCAPTIONHEIGHT, lpnm->iSmCaptionHeight, NULL, fWinIni ) &&
1771 set_entry( &entry_MENUWIDTH, lpnm->iMenuWidth, NULL, fWinIni ) &&
1772 set_entry( &entry_MENUHEIGHT, lpnm->iMenuHeight, NULL, fWinIni ) &&
1773 set_entry( &entry_MENULOGFONT, 0, &lpnm->lfMenuFont, fWinIni ) &&
1774 set_entry( &entry_CAPTIONLOGFONT, 0, &lpnm->lfCaptionFont, fWinIni ) &&
1775 set_entry( &entry_SMCAPTIONLOGFONT, 0, &lpnm->lfSmCaptionFont, fWinIni ) &&
1776 set_entry( &entry_STATUSLOGFONT, 0, &lpnm->lfStatusFont, fWinIni ) &&
1777 set_entry( &entry_MESSAGELOGFONT, 0, &lpnm->lfMessageFont, fWinIni );
1779 break;
1781 case SPI_GETMINIMIZEDMETRICS:
1783 MINIMIZEDMETRICS * lpMm = pvParam;
1784 if (lpMm && lpMm->cbSize == sizeof(*lpMm)) {
1785 ret = get_entry( &entry_MINWIDTH, 0, &lpMm->iWidth ) &&
1786 get_entry( &entry_MINHORZGAP, 0, &lpMm->iHorzGap ) &&
1787 get_entry( &entry_MINVERTGAP, 0, &lpMm->iVertGap ) &&
1788 get_entry( &entry_MINARRANGE, 0, &lpMm->iArrange );
1789 lpMm->iWidth = max( 0, lpMm->iWidth );
1790 lpMm->iHorzGap = max( 0, lpMm->iHorzGap );
1791 lpMm->iVertGap = max( 0, lpMm->iVertGap );
1792 lpMm->iArrange &= 0x0f;
1794 break;
1796 case SPI_SETMINIMIZEDMETRICS:
1798 MINIMIZEDMETRICS * lpMm = pvParam;
1799 if (lpMm && lpMm->cbSize == sizeof(*lpMm))
1800 ret = set_entry( &entry_MINWIDTH, max( 0, lpMm->iWidth ), NULL, fWinIni ) &&
1801 set_entry( &entry_MINHORZGAP, max( 0, lpMm->iHorzGap ), NULL, fWinIni ) &&
1802 set_entry( &entry_MINVERTGAP, max( 0, lpMm->iVertGap ), NULL, fWinIni ) &&
1803 set_entry( &entry_MINARRANGE, lpMm->iArrange & 0x0f, NULL, fWinIni );
1804 break;
1806 case SPI_GETICONMETRICS:
1808 LPICONMETRICSW lpIcon = pvParam;
1809 if(lpIcon && lpIcon->cbSize == sizeof(*lpIcon))
1811 ret = get_entry( &entry_ICONHORIZONTALSPACING, 0, &lpIcon->iHorzSpacing ) &&
1812 get_entry( &entry_ICONVERTICALSPACING, 0, &lpIcon->iVertSpacing ) &&
1813 get_entry( &entry_ICONTITLEWRAP, 0, &lpIcon->iTitleWrap ) &&
1814 get_entry( &entry_ICONTITLELOGFONT, 0, &lpIcon->lfFont );
1816 break;
1818 case SPI_SETICONMETRICS:
1820 LPICONMETRICSW lpIcon = pvParam;
1821 if (lpIcon && lpIcon->cbSize == sizeof(*lpIcon))
1822 ret = set_entry( &entry_ICONVERTICALSPACING, max(32,lpIcon->iVertSpacing), NULL, fWinIni ) &&
1823 set_entry( &entry_ICONHORIZONTALSPACING, max(32,lpIcon->iHorzSpacing), NULL, fWinIni ) &&
1824 set_entry( &entry_ICONTITLEWRAP, lpIcon->iTitleWrap, NULL, fWinIni ) &&
1825 set_entry( &entry_ICONTITLELOGFONT, 0, &lpIcon->lfFont, fWinIni );
1826 break;
1829 case SPI_SETWORKAREA: /* 47 WINVER >= 0x400 */
1831 if (!pvParam) return FALSE;
1833 spi_idx = SPI_SETWORKAREA_IDX;
1834 work_area = *(RECT*)pvParam;
1835 spi_loaded[spi_idx] = TRUE;
1836 ret = TRUE;
1837 break;
1840 case SPI_GETWORKAREA: /* 48 WINVER >= 0x400 */
1842 if (!pvParam) return FALSE;
1844 spi_idx = SPI_SETWORKAREA_IDX;
1845 if (!spi_loaded[spi_idx])
1847 work_area = get_primary_monitor_rect();
1848 EnumDisplayMonitors( 0, NULL, enum_monitors, (LPARAM)&work_area );
1849 spi_loaded[spi_idx] = TRUE;
1851 *(RECT*)pvParam = work_area;
1852 ret = TRUE;
1853 TRACE("work area %s\n", wine_dbgstr_rect( &work_area ));
1854 break;
1857 WINE_SPI_FIXME(SPI_SETPENWINDOWS); /* 49 WINVER >= 0x400 */
1859 case SPI_GETFILTERKEYS: /* 50 */
1861 LPFILTERKEYS lpFilterKeys = pvParam;
1862 WARN("SPI_GETFILTERKEYS not fully implemented\n");
1863 if (lpFilterKeys && lpFilterKeys->cbSize == sizeof(FILTERKEYS))
1865 /* Indicate that no FilterKeys feature available */
1866 lpFilterKeys->dwFlags = 0;
1867 lpFilterKeys->iWaitMSec = 0;
1868 lpFilterKeys->iDelayMSec = 0;
1869 lpFilterKeys->iRepeatMSec = 0;
1870 lpFilterKeys->iBounceMSec = 0;
1871 ret = TRUE;
1873 break;
1875 WINE_SPI_FIXME(SPI_SETFILTERKEYS); /* 51 */
1877 case SPI_GETTOGGLEKEYS: /* 52 */
1879 LPTOGGLEKEYS lpToggleKeys = pvParam;
1880 WARN("SPI_GETTOGGLEKEYS not fully implemented\n");
1881 if (lpToggleKeys && lpToggleKeys->cbSize == sizeof(TOGGLEKEYS))
1883 /* Indicate that no ToggleKeys feature available */
1884 lpToggleKeys->dwFlags = 0;
1885 ret = TRUE;
1887 break;
1889 WINE_SPI_FIXME(SPI_SETTOGGLEKEYS); /* 53 */
1891 case SPI_GETMOUSEKEYS: /* 54 */
1893 LPMOUSEKEYS lpMouseKeys = pvParam;
1894 WARN("SPI_GETMOUSEKEYS not fully implemented\n");
1895 if (lpMouseKeys && lpMouseKeys->cbSize == sizeof(MOUSEKEYS))
1897 /* Indicate that no MouseKeys feature available */
1898 lpMouseKeys->dwFlags = 0;
1899 lpMouseKeys->iMaxSpeed = 360;
1900 lpMouseKeys->iTimeToMaxSpeed = 1000;
1901 lpMouseKeys->iCtrlSpeed = 0;
1902 lpMouseKeys->dwReserved1 = 0;
1903 lpMouseKeys->dwReserved2 = 0;
1904 ret = TRUE;
1906 break;
1908 WINE_SPI_FIXME(SPI_SETMOUSEKEYS); /* 55 */
1910 case SPI_GETSHOWSOUNDS:
1911 ret = get_entry( &entry_SHOWSOUNDS, uiParam, pvParam );
1912 break;
1913 case SPI_SETSHOWSOUNDS:
1914 ret = set_entry( &entry_SHOWSOUNDS, uiParam, pvParam, fWinIni );
1915 break;
1917 case SPI_GETSTICKYKEYS: /* 58 */
1919 LPSTICKYKEYS lpStickyKeys = pvParam;
1920 WARN("SPI_GETSTICKYKEYS not fully implemented\n");
1921 if (lpStickyKeys && lpStickyKeys->cbSize == sizeof(STICKYKEYS))
1923 /* Indicate that no StickyKeys feature available */
1924 lpStickyKeys->dwFlags = 0;
1925 ret = TRUE;
1927 break;
1929 WINE_SPI_FIXME(SPI_SETSTICKYKEYS); /* 59 */
1931 case SPI_GETACCESSTIMEOUT: /* 60 */
1933 LPACCESSTIMEOUT lpAccessTimeout = pvParam;
1934 WARN("SPI_GETACCESSTIMEOUT not fully implemented\n");
1935 if (lpAccessTimeout && lpAccessTimeout->cbSize == sizeof(ACCESSTIMEOUT))
1937 /* Indicate that no accessibility features timeout is available */
1938 lpAccessTimeout->dwFlags = 0;
1939 lpAccessTimeout->iTimeOutMSec = 0;
1940 ret = TRUE;
1942 break;
1944 WINE_SPI_FIXME(SPI_SETACCESSTIMEOUT); /* 61 */
1946 case SPI_GETSERIALKEYS: /* 62 WINVER >= 0x400 */
1948 LPSERIALKEYSW lpSerialKeysW = pvParam;
1949 WARN("SPI_GETSERIALKEYS not fully implemented\n");
1950 if (lpSerialKeysW && lpSerialKeysW->cbSize == sizeof(SERIALKEYSW))
1952 /* Indicate that no SerialKeys feature available */
1953 lpSerialKeysW->dwFlags = 0;
1954 lpSerialKeysW->lpszActivePort = NULL;
1955 lpSerialKeysW->lpszPort = NULL;
1956 lpSerialKeysW->iBaudRate = 0;
1957 lpSerialKeysW->iPortState = 0;
1958 ret = TRUE;
1960 break;
1962 WINE_SPI_FIXME(SPI_SETSERIALKEYS); /* 63 WINVER >= 0x400 */
1964 case SPI_GETSOUNDSENTRY: /* 64 */
1966 LPSOUNDSENTRYW lpSoundSentryW = pvParam;
1967 WARN("SPI_GETSOUNDSENTRY not fully implemented\n");
1968 if (lpSoundSentryW && lpSoundSentryW->cbSize == sizeof(SOUNDSENTRYW))
1970 /* Indicate that no SoundSentry feature available */
1971 lpSoundSentryW->dwFlags = 0;
1972 lpSoundSentryW->iFSTextEffect = 0;
1973 lpSoundSentryW->iFSTextEffectMSec = 0;
1974 lpSoundSentryW->iFSTextEffectColorBits = 0;
1975 lpSoundSentryW->iFSGrafEffect = 0;
1976 lpSoundSentryW->iFSGrafEffectMSec = 0;
1977 lpSoundSentryW->iFSGrafEffectColor = 0;
1978 lpSoundSentryW->iWindowsEffect = 0;
1979 lpSoundSentryW->iWindowsEffectMSec = 0;
1980 lpSoundSentryW->lpszWindowsEffectDLL = 0;
1981 lpSoundSentryW->iWindowsEffectOrdinal = 0;
1982 ret = TRUE;
1984 break;
1986 WINE_SPI_FIXME(SPI_SETSOUNDSENTRY); /* 65 */
1988 case SPI_GETHIGHCONTRAST: /* 66 WINVER >= 0x400 */
1990 LPHIGHCONTRASTW lpHighContrastW = pvParam;
1991 WARN("SPI_GETHIGHCONTRAST not fully implemented\n");
1992 if (lpHighContrastW && lpHighContrastW->cbSize == sizeof(HIGHCONTRASTW))
1994 /* Indicate that no high contrast feature available */
1995 lpHighContrastW->dwFlags = 0;
1996 lpHighContrastW->lpszDefaultScheme = NULL;
1997 ret = TRUE;
1999 break;
2001 WINE_SPI_FIXME(SPI_SETHIGHCONTRAST); /* 67 WINVER >= 0x400 */
2003 case SPI_GETKEYBOARDPREF:
2004 ret = get_entry( &entry_KEYBOARDPREF, uiParam, pvParam );
2005 break;
2006 case SPI_SETKEYBOARDPREF:
2007 ret = set_entry( &entry_KEYBOARDPREF, uiParam, pvParam, fWinIni );
2008 break;
2009 case SPI_GETSCREENREADER:
2010 ret = get_entry( &entry_SCREENREADER, uiParam, pvParam );
2011 break;
2012 case SPI_SETSCREENREADER:
2013 ret = set_entry( &entry_SCREENREADER, uiParam, pvParam, fWinIni );
2014 break;
2016 case SPI_GETANIMATION: /* 72 WINVER >= 0x400 */
2018 LPANIMATIONINFO lpAnimInfo = pvParam;
2020 /* Tell it "disabled" */
2021 if (lpAnimInfo && lpAnimInfo->cbSize == sizeof(ANIMATIONINFO))
2023 lpAnimInfo->iMinAnimate = 0; /* Minimize and restore animation is disabled (nonzero == enabled) */
2024 ret = TRUE;
2026 break;
2028 WINE_SPI_WARN(SPI_SETANIMATION); /* 73 WINVER >= 0x400 */
2030 case SPI_GETFONTSMOOTHING:
2031 ret = get_entry( &entry_FONTSMOOTHING, uiParam, pvParam );
2032 if (ret) *(UINT *)pvParam = (*(UINT *)pvParam != 0);
2033 break;
2034 case SPI_SETFONTSMOOTHING:
2035 uiParam = uiParam ? 2 : 0; /* Win NT4/2k/XP behavior */
2036 ret = set_entry( &entry_FONTSMOOTHING, uiParam, pvParam, fWinIni );
2037 break;
2038 case SPI_SETDRAGWIDTH:
2039 ret = set_entry( &entry_DRAGWIDTH, uiParam, pvParam, fWinIni );
2040 break;
2041 case SPI_SETDRAGHEIGHT:
2042 ret = set_entry( &entry_DRAGHEIGHT, uiParam, pvParam, fWinIni );
2043 break;
2045 WINE_SPI_FIXME(SPI_SETHANDHELD); /* 78 WINVER >= 0x400 */
2047 WINE_SPI_FIXME(SPI_GETLOWPOWERTIMEOUT); /* 79 WINVER >= 0x400 */
2048 WINE_SPI_FIXME(SPI_GETPOWEROFFTIMEOUT); /* 80 WINVER >= 0x400 */
2049 WINE_SPI_FIXME(SPI_SETLOWPOWERTIMEOUT); /* 81 WINVER >= 0x400 */
2050 WINE_SPI_FIXME(SPI_SETPOWEROFFTIMEOUT); /* 82 WINVER >= 0x400 */
2052 case SPI_GETLOWPOWERACTIVE:
2053 ret = get_entry( &entry_LOWPOWERACTIVE, uiParam, pvParam );
2054 break;
2055 case SPI_SETLOWPOWERACTIVE:
2056 ret = set_entry( &entry_LOWPOWERACTIVE, uiParam, pvParam, fWinIni );
2057 break;
2058 case SPI_GETPOWEROFFACTIVE:
2059 ret = get_entry( &entry_POWEROFFACTIVE, uiParam, pvParam );
2060 break;
2061 case SPI_SETPOWEROFFACTIVE:
2062 ret = set_entry( &entry_POWEROFFACTIVE, uiParam, pvParam, fWinIni );
2063 break;
2065 WINE_SPI_FIXME(SPI_SETCURSORS); /* 87 WINVER >= 0x400 */
2066 WINE_SPI_FIXME(SPI_SETICONS); /* 88 WINVER >= 0x400 */
2068 case SPI_GETDEFAULTINPUTLANG: /* 89 WINVER >= 0x400 */
2069 ret = GetKeyboardLayout(0) != 0;
2070 break;
2072 WINE_SPI_FIXME(SPI_SETDEFAULTINPUTLANG); /* 90 WINVER >= 0x400 */
2074 WINE_SPI_FIXME(SPI_SETLANGTOGGLE); /* 91 WINVER >= 0x400 */
2076 case SPI_GETWINDOWSEXTENSION: /* 92 WINVER >= 0x400 */
2077 WARN("pretend no support for Win9x Plus! for now.\n");
2078 ret = FALSE; /* yes, this is the result value */
2079 break;
2080 case SPI_SETMOUSETRAILS:
2081 ret = set_entry( &entry_MOUSETRAILS, uiParam, pvParam, fWinIni );
2082 break;
2083 case SPI_GETMOUSETRAILS:
2084 ret = get_entry( &entry_MOUSETRAILS, uiParam, pvParam );
2085 break;
2086 case SPI_GETSNAPTODEFBUTTON:
2087 ret = get_entry( &entry_SNAPTODEFBUTTON, uiParam, pvParam );
2088 break;
2089 case SPI_SETSNAPTODEFBUTTON:
2090 ret = set_entry( &entry_SNAPTODEFBUTTON, uiParam, pvParam, fWinIni );
2091 break;
2092 case SPI_SETSCREENSAVERRUNNING:
2093 ret = set_entry( &entry_SCREENSAVERRUNNING, uiParam, pvParam, fWinIni );
2094 break;
2095 case SPI_GETMOUSEHOVERWIDTH:
2096 ret = get_entry( &entry_MOUSEHOVERWIDTH, uiParam, pvParam );
2097 break;
2098 case SPI_SETMOUSEHOVERWIDTH:
2099 ret = set_entry( &entry_MOUSEHOVERWIDTH, uiParam, pvParam, fWinIni );
2100 break;
2101 case SPI_GETMOUSEHOVERHEIGHT:
2102 ret = get_entry( &entry_MOUSEHOVERHEIGHT, uiParam, pvParam );
2103 break;
2104 case SPI_SETMOUSEHOVERHEIGHT:
2105 ret = set_entry( &entry_MOUSEHOVERHEIGHT, uiParam, pvParam, fWinIni );
2106 break;
2107 case SPI_GETMOUSEHOVERTIME:
2108 ret = get_entry( &entry_MOUSEHOVERTIME, uiParam, pvParam );
2109 break;
2110 case SPI_SETMOUSEHOVERTIME:
2111 ret = set_entry( &entry_MOUSEHOVERTIME, uiParam, pvParam, fWinIni );
2112 break;
2113 case SPI_GETWHEELSCROLLLINES:
2114 ret = get_entry( &entry_WHEELSCROLLLINES, uiParam, pvParam );
2115 break;
2116 case SPI_SETWHEELSCROLLLINES:
2117 ret = set_entry( &entry_WHEELSCROLLLINES, uiParam, pvParam, fWinIni );
2118 break;
2119 case SPI_GETMENUSHOWDELAY:
2120 ret = get_entry( &entry_MENUSHOWDELAY, uiParam, pvParam );
2121 break;
2122 case SPI_SETMENUSHOWDELAY:
2123 ret = set_entry( &entry_MENUSHOWDELAY, uiParam, pvParam, fWinIni );
2124 break;
2125 case SPI_GETWHEELSCROLLCHARS:
2126 ret = get_entry( &entry_WHEELSCROLLCHARS, uiParam, pvParam );
2127 break;
2128 case SPI_SETWHEELSCROLLCHARS:
2129 ret = set_entry( &entry_WHEELSCROLLCHARS, uiParam, pvParam, fWinIni );
2130 break;
2132 WINE_SPI_FIXME(SPI_GETSHOWIMEUI); /* 110 _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
2133 WINE_SPI_FIXME(SPI_SETSHOWIMEUI); /* 111 _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
2135 case SPI_GETMOUSESPEED:
2136 ret = get_entry( &entry_MOUSESPEED, uiParam, pvParam );
2137 break;
2138 case SPI_SETMOUSESPEED:
2139 ret = set_entry( &entry_MOUSESPEED, uiParam, pvParam, fWinIni );
2140 break;
2141 case SPI_GETSCREENSAVERRUNNING:
2142 ret = get_entry( &entry_SCREENSAVERRUNNING, uiParam, pvParam );
2143 break;
2144 case SPI_GETDESKWALLPAPER:
2145 ret = get_entry( &entry_DESKWALLPAPER, uiParam, pvParam );
2146 break;
2147 case SPI_GETACTIVEWINDOWTRACKING:
2148 ret = get_entry( &entry_ACTIVEWINDOWTRACKING, uiParam, pvParam );
2149 break;
2150 case SPI_SETACTIVEWINDOWTRACKING:
2151 ret = set_entry( &entry_ACTIVEWINDOWTRACKING, uiParam, pvParam, fWinIni );
2152 break;
2153 case SPI_GETMENUANIMATION:
2154 ret = get_entry( &entry_MENUANIMATION, uiParam, pvParam );
2155 break;
2156 case SPI_SETMENUANIMATION:
2157 ret = set_entry( &entry_MENUANIMATION, uiParam, pvParam, fWinIni );
2158 break;
2159 case SPI_GETCOMBOBOXANIMATION:
2160 ret = get_entry( &entry_COMBOBOXANIMATION, uiParam, pvParam );
2161 break;
2162 case SPI_SETCOMBOBOXANIMATION:
2163 ret = set_entry( &entry_COMBOBOXANIMATION, uiParam, pvParam, fWinIni );
2164 break;
2165 case SPI_GETLISTBOXSMOOTHSCROLLING:
2166 ret = get_entry( &entry_LISTBOXSMOOTHSCROLLING, uiParam, pvParam );
2167 break;
2168 case SPI_SETLISTBOXSMOOTHSCROLLING:
2169 ret = set_entry( &entry_LISTBOXSMOOTHSCROLLING, uiParam, pvParam, fWinIni );
2170 break;
2171 case SPI_GETGRADIENTCAPTIONS:
2172 ret = get_entry( &entry_GRADIENTCAPTIONS, uiParam, pvParam );
2173 break;
2174 case SPI_SETGRADIENTCAPTIONS:
2175 ret = set_entry( &entry_GRADIENTCAPTIONS, uiParam, pvParam, fWinIni );
2176 break;
2177 case SPI_GETKEYBOARDCUES:
2178 ret = get_entry( &entry_KEYBOARDCUES, uiParam, pvParam );
2179 break;
2180 case SPI_SETKEYBOARDCUES:
2181 ret = set_entry( &entry_KEYBOARDCUES, uiParam, pvParam, fWinIni );
2182 break;
2183 case SPI_GETACTIVEWNDTRKZORDER:
2184 ret = get_entry( &entry_ACTIVEWNDTRKZORDER, uiParam, pvParam );
2185 break;
2186 case SPI_SETACTIVEWNDTRKZORDER:
2187 ret = set_entry( &entry_ACTIVEWNDTRKZORDER, uiParam, pvParam, fWinIni );
2188 break;
2189 case SPI_GETHOTTRACKING:
2190 ret = get_entry( &entry_HOTTRACKING, uiParam, pvParam );
2191 break;
2192 case SPI_SETHOTTRACKING:
2193 ret = set_entry( &entry_HOTTRACKING, uiParam, pvParam, fWinIni );
2194 break;
2195 case SPI_GETMENUFADE:
2196 ret = get_entry( &entry_MENUFADE, uiParam, pvParam );
2197 break;
2198 case SPI_SETMENUFADE:
2199 ret = set_entry( &entry_MENUFADE, uiParam, pvParam, fWinIni );
2200 break;
2201 case SPI_GETSELECTIONFADE:
2202 ret = get_entry( &entry_SELECTIONFADE, uiParam, pvParam );
2203 break;
2204 case SPI_SETSELECTIONFADE:
2205 ret = set_entry( &entry_SELECTIONFADE, uiParam, pvParam, fWinIni );
2206 break;
2207 case SPI_GETTOOLTIPANIMATION:
2208 ret = get_entry( &entry_TOOLTIPANIMATION, uiParam, pvParam );
2209 break;
2210 case SPI_SETTOOLTIPANIMATION:
2211 ret = set_entry( &entry_TOOLTIPANIMATION, uiParam, pvParam, fWinIni );
2212 break;
2213 case SPI_GETTOOLTIPFADE:
2214 ret = get_entry( &entry_TOOLTIPFADE, uiParam, pvParam );
2215 break;
2216 case SPI_SETTOOLTIPFADE:
2217 ret = set_entry( &entry_TOOLTIPFADE, uiParam, pvParam, fWinIni );
2218 break;
2219 case SPI_GETCURSORSHADOW:
2220 ret = get_entry( &entry_CURSORSHADOW, uiParam, pvParam );
2221 break;
2222 case SPI_SETCURSORSHADOW:
2223 ret = set_entry( &entry_CURSORSHADOW, uiParam, pvParam, fWinIni );
2224 break;
2225 case SPI_GETMOUSESONAR:
2226 ret = get_entry( &entry_MOUSESONAR, uiParam, pvParam );
2227 break;
2228 case SPI_SETMOUSESONAR:
2229 ret = set_entry( &entry_MOUSESONAR, uiParam, pvParam, fWinIni );
2230 break;
2231 case SPI_GETMOUSECLICKLOCK:
2232 ret = get_entry( &entry_MOUSECLICKLOCK, uiParam, pvParam );
2233 break;
2234 case SPI_SETMOUSECLICKLOCK:
2235 ret = set_entry( &entry_MOUSECLICKLOCK, uiParam, pvParam, fWinIni );
2236 break;
2237 case SPI_GETMOUSEVANISH:
2238 ret = get_entry( &entry_MOUSEVANISH, uiParam, pvParam );
2239 break;
2240 case SPI_SETMOUSEVANISH:
2241 ret = set_entry( &entry_MOUSEVANISH, uiParam, pvParam, fWinIni );
2242 break;
2243 case SPI_GETFLATMENU:
2244 ret = get_entry( &entry_FLATMENU, uiParam, pvParam );
2245 break;
2246 case SPI_SETFLATMENU:
2247 ret = set_entry( &entry_FLATMENU, uiParam, pvParam, fWinIni );
2248 break;
2249 case SPI_GETDROPSHADOW:
2250 ret = get_entry( &entry_DROPSHADOW, uiParam, pvParam );
2251 break;
2252 case SPI_SETDROPSHADOW:
2253 ret = set_entry( &entry_DROPSHADOW, uiParam, pvParam, fWinIni );
2254 break;
2255 case SPI_GETBLOCKSENDINPUTRESETS:
2256 ret = get_entry( &entry_BLOCKSENDINPUTRESETS, uiParam, pvParam );
2257 break;
2258 case SPI_SETBLOCKSENDINPUTRESETS:
2259 ret = set_entry( &entry_BLOCKSENDINPUTRESETS, uiParam, pvParam, fWinIni );
2260 break;
2261 case SPI_GETUIEFFECTS:
2262 ret = get_entry( &entry_UIEFFECTS, uiParam, pvParam );
2263 break;
2264 case SPI_SETUIEFFECTS:
2265 /* FIXME: this probably should mask other UI effect values when unset */
2266 ret = set_entry( &entry_UIEFFECTS, uiParam, pvParam, fWinIni );
2267 break;
2268 case SPI_GETDISABLEOVERLAPPEDCONTENT:
2269 ret = get_entry( &entry_DISABLEOVERLAPPEDCONTENT, uiParam, pvParam );
2270 break;
2271 case SPI_SETDISABLEOVERLAPPEDCONTENT:
2272 ret = set_entry( &entry_DISABLEOVERLAPPEDCONTENT, uiParam, pvParam, fWinIni );
2273 break;
2274 case SPI_GETCLIENTAREAANIMATION:
2275 ret = get_entry( &entry_CLIENTAREAANIMATION, uiParam, pvParam );
2276 break;
2277 case SPI_SETCLIENTAREAANIMATION:
2278 ret = set_entry( &entry_CLIENTAREAANIMATION, uiParam, pvParam, fWinIni );
2279 break;
2280 case SPI_GETCLEARTYPE:
2281 ret = get_entry( &entry_CLEARTYPE, uiParam, pvParam );
2282 break;
2283 case SPI_SETCLEARTYPE:
2284 ret = set_entry( &entry_CLEARTYPE, uiParam, pvParam, fWinIni );
2285 break;
2286 case SPI_GETSPEECHRECOGNITION:
2287 ret = get_entry( &entry_SPEECHRECOGNITION, uiParam, pvParam );
2288 break;
2289 case SPI_SETSPEECHRECOGNITION:
2290 ret = set_entry( &entry_SPEECHRECOGNITION, uiParam, pvParam, fWinIni );
2291 break;
2292 case SPI_GETFOREGROUNDLOCKTIMEOUT:
2293 ret = get_entry( &entry_FOREGROUNDLOCKTIMEOUT, uiParam, pvParam );
2294 break;
2295 case SPI_SETFOREGROUNDLOCKTIMEOUT:
2296 /* FIXME: this should check that the calling thread
2297 * is able to change the foreground window */
2298 ret = set_entry( &entry_FOREGROUNDLOCKTIMEOUT, uiParam, pvParam, fWinIni );
2299 break;
2300 case SPI_GETACTIVEWNDTRKTIMEOUT:
2301 ret = get_entry( &entry_ACTIVEWNDTRKTIMEOUT, uiParam, pvParam );
2302 break;
2303 case SPI_SETACTIVEWNDTRKTIMEOUT:
2304 ret = get_entry( &entry_ACTIVEWNDTRKTIMEOUT, uiParam, pvParam );
2305 break;
2306 case SPI_GETFOREGROUNDFLASHCOUNT:
2307 ret = get_entry( &entry_FOREGROUNDFLASHCOUNT, uiParam, pvParam );
2308 break;
2309 case SPI_SETFOREGROUNDFLASHCOUNT:
2310 ret = set_entry( &entry_FOREGROUNDFLASHCOUNT, uiParam, pvParam, fWinIni );
2311 break;
2312 case SPI_GETCARETWIDTH:
2313 ret = get_entry( &entry_CARETWIDTH, uiParam, pvParam );
2314 break;
2315 case SPI_SETCARETWIDTH:
2316 ret = set_entry( &entry_CARETWIDTH, uiParam, pvParam, fWinIni );
2317 break;
2318 case SPI_GETMOUSECLICKLOCKTIME:
2319 ret = get_entry( &entry_MOUSECLICKLOCKTIME, uiParam, pvParam );
2320 break;
2321 case SPI_SETMOUSECLICKLOCKTIME:
2322 ret = set_entry( &entry_MOUSECLICKLOCKTIME, uiParam, pvParam, fWinIni );
2323 break;
2324 case SPI_GETFONTSMOOTHINGTYPE:
2325 ret = get_entry( &entry_FONTSMOOTHINGTYPE, uiParam, pvParam );
2326 break;
2327 case SPI_SETFONTSMOOTHINGTYPE:
2328 ret = set_entry( &entry_FONTSMOOTHINGTYPE, uiParam, pvParam, fWinIni );
2329 break;
2330 case SPI_GETFONTSMOOTHINGCONTRAST:
2331 ret = get_entry( &entry_FONTSMOOTHINGCONTRAST, uiParam, pvParam );
2332 break;
2333 case SPI_SETFONTSMOOTHINGCONTRAST:
2334 ret = set_entry( &entry_FONTSMOOTHINGCONTRAST, uiParam, pvParam, fWinIni );
2335 break;
2336 case SPI_GETFOCUSBORDERWIDTH:
2337 ret = get_entry( &entry_FOCUSBORDERWIDTH, uiParam, pvParam );
2338 break;
2339 case SPI_GETFOCUSBORDERHEIGHT:
2340 ret = get_entry( &entry_FOCUSBORDERHEIGHT, uiParam, pvParam );
2341 break;
2342 case SPI_SETFOCUSBORDERWIDTH:
2343 ret = set_entry( &entry_FOCUSBORDERWIDTH, uiParam, pvParam, fWinIni );
2344 break;
2345 case SPI_SETFOCUSBORDERHEIGHT:
2346 ret = set_entry( &entry_FOCUSBORDERHEIGHT, uiParam, pvParam, fWinIni );
2347 break;
2348 case SPI_GETFONTSMOOTHINGORIENTATION:
2349 ret = get_entry( &entry_FONTSMOOTHINGORIENTATION, uiParam, pvParam );
2350 break;
2351 case SPI_SETFONTSMOOTHINGORIENTATION:
2352 ret = set_entry( &entry_FONTSMOOTHINGORIENTATION, uiParam, pvParam, fWinIni );
2353 break;
2354 case SPI_GETAUDIODESCRIPTION:
2356 AUDIODESCRIPTION *audio = pvParam;
2357 if (audio && audio->cbSize == sizeof(AUDIODESCRIPTION) && uiParam == sizeof(AUDIODESCRIPTION) )
2359 ret = get_entry( &entry_AUDIODESC_ON, 0, &audio->Enabled ) &&
2360 get_entry( &entry_AUDIODESC_LOCALE, 0, &audio->Locale );
2362 break;
2364 case SPI_SETAUDIODESCRIPTION:
2366 AUDIODESCRIPTION *audio = pvParam;
2367 if (audio && audio->cbSize == sizeof(AUDIODESCRIPTION) && uiParam == sizeof(AUDIODESCRIPTION) )
2369 ret = set_entry( &entry_AUDIODESC_ON, 0, &audio->Enabled, fWinIni) &&
2370 set_entry( &entry_AUDIODESC_LOCALE, 0, &audio->Locale, fWinIni );
2372 break;
2374 default:
2375 FIXME( "Unknown action: %u\n", uiAction );
2376 SetLastError( ERROR_INVALID_SPI_VALUE );
2377 ret = FALSE;
2378 break;
2381 if (ret)
2382 SYSPARAMS_NotifyChange( uiAction, fWinIni );
2383 TRACE("(%u, %u, %p, %u) ret %d\n",
2384 uiAction, uiParam, pvParam, fWinIni, ret);
2385 return ret;
2387 #undef WINE_SPI_FIXME
2388 #undef WINE_SPI_WARN
2392 /***********************************************************************
2393 * SystemParametersInfoA (USER32.@)
2395 BOOL WINAPI SystemParametersInfoA( UINT uiAction, UINT uiParam,
2396 PVOID pvParam, UINT fuWinIni )
2398 BOOL ret;
2400 TRACE("(%u, %u, %p, %u)\n", uiAction, uiParam, pvParam, fuWinIni);
2402 switch (uiAction)
2404 case SPI_SETDESKWALLPAPER: /* 20 */
2405 case SPI_SETDESKPATTERN: /* 21 */
2407 WCHAR buffer[256];
2408 if (pvParam)
2409 if (!MultiByteToWideChar( CP_ACP, 0, pvParam, -1, buffer, ARRAY_SIZE( buffer )))
2410 buffer[ARRAY_SIZE(buffer)-1] = 0;
2411 ret = SystemParametersInfoW( uiAction, uiParam, pvParam ? buffer : NULL, fuWinIni );
2412 break;
2415 case SPI_GETICONTITLELOGFONT: /* 31 */
2417 LOGFONTW tmp;
2418 ret = SystemParametersInfoW( uiAction, uiParam, pvParam ? &tmp : NULL, fuWinIni );
2419 if (ret && pvParam)
2420 SYSPARAMS_LogFont32WTo32A( &tmp, pvParam );
2421 break;
2424 case SPI_GETNONCLIENTMETRICS: /* 41 WINVER >= 0x400 */
2426 NONCLIENTMETRICSW tmp;
2427 LPNONCLIENTMETRICSA lpnmA = pvParam;
2428 if (lpnmA && (lpnmA->cbSize == sizeof(NONCLIENTMETRICSA) ||
2429 lpnmA->cbSize == FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth)))
2431 tmp.cbSize = sizeof(NONCLIENTMETRICSW);
2432 ret = SystemParametersInfoW( uiAction, uiParam, &tmp, fuWinIni );
2433 if (ret)
2434 SYSPARAMS_NonClientMetrics32WTo32A( &tmp, lpnmA );
2436 else
2437 ret = FALSE;
2438 break;
2441 case SPI_SETNONCLIENTMETRICS: /* 42 WINVER >= 0x400 */
2443 NONCLIENTMETRICSW tmp;
2444 LPNONCLIENTMETRICSA lpnmA = pvParam;
2445 if (lpnmA && (lpnmA->cbSize == sizeof(NONCLIENTMETRICSA) ||
2446 lpnmA->cbSize == FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth)))
2448 tmp.cbSize = sizeof(NONCLIENTMETRICSW);
2449 SYSPARAMS_NonClientMetrics32ATo32W( lpnmA, &tmp );
2450 ret = SystemParametersInfoW( uiAction, uiParam, &tmp, fuWinIni );
2452 else
2453 ret = FALSE;
2454 break;
2457 case SPI_GETICONMETRICS: /* 45 WINVER >= 0x400 */
2459 ICONMETRICSW tmp;
2460 LPICONMETRICSA lpimA = pvParam;
2461 if (lpimA && lpimA->cbSize == sizeof(ICONMETRICSA))
2463 tmp.cbSize = sizeof(ICONMETRICSW);
2464 ret = SystemParametersInfoW( uiAction, uiParam, &tmp, fuWinIni );
2465 if (ret)
2467 lpimA->iHorzSpacing = tmp.iHorzSpacing;
2468 lpimA->iVertSpacing = tmp.iVertSpacing;
2469 lpimA->iTitleWrap = tmp.iTitleWrap;
2470 SYSPARAMS_LogFont32WTo32A( &tmp.lfFont, &lpimA->lfFont );
2473 else
2474 ret = FALSE;
2475 break;
2478 case SPI_SETICONMETRICS: /* 46 WINVER >= 0x400 */
2480 ICONMETRICSW tmp;
2481 LPICONMETRICSA lpimA = pvParam;
2482 if (lpimA && lpimA->cbSize == sizeof(ICONMETRICSA))
2484 tmp.cbSize = sizeof(ICONMETRICSW);
2485 tmp.iHorzSpacing = lpimA->iHorzSpacing;
2486 tmp.iVertSpacing = lpimA->iVertSpacing;
2487 tmp.iTitleWrap = lpimA->iTitleWrap;
2488 SYSPARAMS_LogFont32ATo32W( &lpimA->lfFont, &tmp.lfFont);
2489 ret = SystemParametersInfoW( uiAction, uiParam, &tmp, fuWinIni );
2491 else
2492 ret = FALSE;
2493 break;
2496 case SPI_GETHIGHCONTRAST: /* 66 WINVER >= 0x400 */
2498 HIGHCONTRASTW tmp;
2499 LPHIGHCONTRASTA lphcA = pvParam;
2500 if (lphcA && lphcA->cbSize == sizeof(HIGHCONTRASTA))
2502 tmp.cbSize = sizeof(HIGHCONTRASTW);
2503 ret = SystemParametersInfoW( uiAction, uiParam, &tmp, fuWinIni );
2504 if (ret)
2506 lphcA->dwFlags = tmp.dwFlags;
2507 lphcA->lpszDefaultScheme = NULL; /* FIXME? */
2510 else
2511 ret = FALSE;
2512 break;
2515 case SPI_GETDESKWALLPAPER: /* 115 */
2517 WCHAR buffer[MAX_PATH];
2518 ret = (SystemParametersInfoW( SPI_GETDESKWALLPAPER, uiParam, buffer, fuWinIni ) &&
2519 WideCharToMultiByte(CP_ACP, 0, buffer, -1, pvParam, uiParam, NULL, NULL));
2520 break;
2523 default:
2524 ret = SystemParametersInfoW( uiAction, uiParam, pvParam, fuWinIni );
2525 break;
2527 return ret;
2531 /***********************************************************************
2532 * GetSystemMetrics (USER32.@)
2534 INT WINAPI GetSystemMetrics( INT index )
2536 NONCLIENTMETRICSW ncm;
2537 MINIMIZEDMETRICS mm;
2538 ICONMETRICSW im;
2539 RECT rect;
2540 UINT ret;
2541 HDC hdc;
2543 /* some metrics are dynamic */
2544 switch (index)
2546 case SM_CXVSCROLL:
2547 case SM_CYHSCROLL:
2548 get_entry( &entry_SCROLLWIDTH, 0, &ret );
2549 return max( ret, 8 );
2550 case SM_CYCAPTION:
2551 ncm.cbSize = sizeof(ncm);
2552 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2553 return ncm.iCaptionHeight + 1;
2554 case SM_CXBORDER:
2555 case SM_CYBORDER:
2556 /* SM_C{X,Y}BORDER always returns 1 regardless of 'BorderWidth' value in registry */
2557 return 1;
2558 case SM_CXDLGFRAME:
2559 case SM_CYDLGFRAME:
2560 return 3;
2561 case SM_CYVTHUMB:
2562 case SM_CXHTHUMB:
2563 case SM_CYVSCROLL:
2564 case SM_CXHSCROLL:
2565 get_entry( &entry_SCROLLHEIGHT, 0, &ret );
2566 return max( ret, 8 );
2567 case SM_CXICON:
2568 case SM_CYICON:
2569 return map_to_dpi( 32, GetDpiForSystem() );
2570 case SM_CXCURSOR:
2571 case SM_CYCURSOR:
2572 ret = map_to_dpi( 32, GetDpiForSystem() );
2573 if (ret >= 64) return 64;
2574 if (ret >= 48) return 48;
2575 return 32;
2576 case SM_CYMENU:
2577 ncm.cbSize = sizeof(ncm);
2578 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2579 return ncm.iMenuHeight + 1;
2580 case SM_CXFULLSCREEN:
2581 /* see the remark for SM_CXMAXIMIZED, at least this formulation is
2582 * correct */
2583 return GetSystemMetrics( SM_CXMAXIMIZED) - 2 * GetSystemMetrics( SM_CXFRAME);
2584 case SM_CYFULLSCREEN:
2585 /* see the remark for SM_CYMAXIMIZED, at least this formulation is
2586 * correct */
2587 return GetSystemMetrics( SM_CYMAXIMIZED) - GetSystemMetrics( SM_CYMIN);
2588 case SM_CYKANJIWINDOW:
2589 return 0;
2590 case SM_MOUSEPRESENT:
2591 return 1;
2592 case SM_DEBUG:
2593 return 0;
2594 case SM_SWAPBUTTON:
2595 get_entry( &entry_MOUSEBUTTONSWAP, 0, &ret );
2596 return ret;
2597 case SM_RESERVED1:
2598 case SM_RESERVED2:
2599 case SM_RESERVED3:
2600 case SM_RESERVED4:
2601 return 0;
2602 case SM_CXMIN:
2603 ncm.cbSize = sizeof(ncm);
2604 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2605 hdc = get_display_dc();
2606 get_text_metr_size( hdc, &ncm.lfCaptionFont, NULL, &ret );
2607 release_display_dc( hdc );
2608 return 3 * ncm.iCaptionWidth + ncm.iCaptionHeight + 4 * ret + 2 * GetSystemMetrics(SM_CXFRAME) + 4;
2609 case SM_CYMIN:
2610 return GetSystemMetrics( SM_CYCAPTION) + 2 * GetSystemMetrics( SM_CYFRAME);
2611 case SM_CXSIZE:
2612 get_entry( &entry_CAPTIONWIDTH, 0, &ret );
2613 return max( ret, 8 );
2614 case SM_CYSIZE:
2615 ncm.cbSize = sizeof(ncm);
2616 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2617 return ncm.iCaptionHeight;
2618 case SM_CXFRAME:
2619 get_entry( &entry_BORDER, 0, &ret );
2620 ret = max( ret, 1 );
2621 return GetSystemMetrics(SM_CXDLGFRAME) + ret;
2622 case SM_CYFRAME:
2623 get_entry( &entry_BORDER, 0, &ret );
2624 ret = max( ret, 1 );
2625 return GetSystemMetrics(SM_CYDLGFRAME) + ret;
2626 case SM_CXMINTRACK:
2627 return GetSystemMetrics(SM_CXMIN);
2628 case SM_CYMINTRACK:
2629 return GetSystemMetrics(SM_CYMIN);
2630 case SM_CXDOUBLECLK:
2631 get_entry( &entry_DOUBLECLKWIDTH, 0, &ret );
2632 return ret;
2633 case SM_CYDOUBLECLK:
2634 get_entry( &entry_DOUBLECLKHEIGHT, 0, &ret );
2635 return ret;
2636 case SM_CXICONSPACING:
2637 im.cbSize = sizeof(im);
2638 SystemParametersInfoW( SPI_GETICONMETRICS, sizeof(im), &im, 0 );
2639 return im.iHorzSpacing;
2640 case SM_CYICONSPACING:
2641 im.cbSize = sizeof(im);
2642 SystemParametersInfoW( SPI_GETICONMETRICS, sizeof(im), &im, 0 );
2643 return im.iVertSpacing;
2644 case SM_MENUDROPALIGNMENT:
2645 SystemParametersInfoW( SPI_GETMENUDROPALIGNMENT, 0, &ret, 0 );
2646 return ret;
2647 case SM_PENWINDOWS:
2648 return 0;
2649 case SM_DBCSENABLED:
2651 CPINFO cpinfo;
2652 GetCPInfo( CP_ACP, &cpinfo );
2653 return (cpinfo.MaxCharSize > 1);
2655 case SM_CMOUSEBUTTONS:
2656 return 3;
2657 case SM_SECURE:
2658 return 0;
2659 case SM_CXEDGE:
2660 return GetSystemMetrics(SM_CXBORDER) + 1;
2661 case SM_CYEDGE:
2662 return GetSystemMetrics(SM_CYBORDER) + 1;
2663 case SM_CXMINSPACING:
2664 mm.cbSize = sizeof(mm);
2665 SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
2666 return GetSystemMetrics(SM_CXMINIMIZED) + mm.iHorzGap;
2667 case SM_CYMINSPACING:
2668 mm.cbSize = sizeof(mm);
2669 SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
2670 return GetSystemMetrics(SM_CYMINIMIZED) + mm.iVertGap;
2671 case SM_CXSMICON:
2672 case SM_CYSMICON:
2673 return map_to_dpi( 16, GetDpiForSystem() ) & ~1;
2674 case SM_CYSMCAPTION:
2675 ncm.cbSize = sizeof(ncm);
2676 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2677 return ncm.iSmCaptionHeight + 1;
2678 case SM_CXSMSIZE:
2679 get_entry( &entry_SMCAPTIONWIDTH, 0, &ret );
2680 return ret;
2681 case SM_CYSMSIZE:
2682 ncm.cbSize = sizeof(ncm);
2683 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2684 return ncm.iSmCaptionHeight;
2685 case SM_CXMENUSIZE:
2686 get_entry( &entry_MENUWIDTH, 0, &ret );
2687 return ret;
2688 case SM_CYMENUSIZE:
2689 ncm.cbSize = sizeof(ncm);
2690 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2691 return ncm.iMenuHeight;
2692 case SM_ARRANGE:
2693 mm.cbSize = sizeof(mm);
2694 SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
2695 return mm.iArrange;
2696 case SM_CXMINIMIZED:
2697 mm.cbSize = sizeof(mm);
2698 SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
2699 return mm.iWidth + 6;
2700 case SM_CYMINIMIZED:
2701 ncm.cbSize = sizeof(ncm);
2702 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2703 return ncm.iCaptionHeight + 6;
2704 case SM_CXMAXTRACK:
2705 return GetSystemMetrics(SM_CXVIRTUALSCREEN) + 4 + 2 * GetSystemMetrics(SM_CXFRAME);
2706 case SM_CYMAXTRACK:
2707 return GetSystemMetrics(SM_CYVIRTUALSCREEN) + 4 + 2 * GetSystemMetrics(SM_CYFRAME);
2708 case SM_CXMAXIMIZED:
2709 /* FIXME: subtract the width of any vertical application toolbars*/
2710 return GetSystemMetrics(SM_CXSCREEN) + 2 * GetSystemMetrics(SM_CXFRAME);
2711 case SM_CYMAXIMIZED:
2712 /* FIXME: subtract the width of any horizontal application toolbars*/
2713 return GetSystemMetrics(SM_CYSCREEN) + 2 * GetSystemMetrics(SM_CYCAPTION);
2714 case SM_NETWORK:
2715 return 3; /* FIXME */
2716 case SM_CLEANBOOT:
2717 return 0; /* 0 = ok, 1 = failsafe, 2 = failsafe + network */
2718 case SM_CXDRAG:
2719 get_entry( &entry_DRAGWIDTH, 0, &ret );
2720 return ret;
2721 case SM_CYDRAG:
2722 get_entry( &entry_DRAGHEIGHT, 0, &ret );
2723 return ret;
2724 case SM_SHOWSOUNDS:
2725 get_entry( &entry_SHOWSOUNDS, 0, &ret );
2726 return ret;
2727 case SM_CXMENUCHECK:
2728 case SM_CYMENUCHECK:
2730 TEXTMETRICW tm;
2731 ncm.cbSize = sizeof(ncm);
2732 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
2733 hdc = get_display_dc();
2734 get_text_metr_size( hdc, &ncm.lfMenuFont, &tm, NULL);
2735 release_display_dc( hdc );
2736 return tm.tmHeight <= 0 ? 13 : ((tm.tmHeight + tm.tmExternalLeading + 1) / 2) * 2 - 1;
2738 case SM_SLOWMACHINE:
2739 return 0; /* Never true */
2740 case SM_MIDEASTENABLED:
2741 return 0; /* FIXME */
2742 case SM_MOUSEWHEELPRESENT:
2743 return 1;
2744 case SM_CXSCREEN:
2745 rect = get_primary_monitor_rect();
2746 return rect.right - rect.left;
2747 case SM_CYSCREEN:
2748 rect = get_primary_monitor_rect();
2749 return rect.bottom - rect.top;
2750 case SM_XVIRTUALSCREEN:
2751 rect = get_virtual_screen_rect();
2752 return rect.left;
2753 case SM_YVIRTUALSCREEN:
2754 rect = get_virtual_screen_rect();
2755 return rect.top;
2756 case SM_CXVIRTUALSCREEN:
2757 rect = get_virtual_screen_rect();
2758 return rect.right - rect.left;
2759 case SM_CYVIRTUALSCREEN:
2760 rect = get_virtual_screen_rect();
2761 return rect.bottom - rect.top;
2762 case SM_CMONITORS:
2763 return get_monitor_count();
2764 case SM_SAMEDISPLAYFORMAT:
2765 return 1;
2766 case SM_IMMENABLED:
2767 return 0; /* FIXME */
2768 case SM_CXFOCUSBORDER:
2769 case SM_CYFOCUSBORDER:
2770 return 1;
2771 case SM_TABLETPC:
2772 case SM_MEDIACENTER:
2773 return 0;
2774 case SM_CMETRICS:
2775 return SM_CMETRICS;
2776 default:
2777 return 0;
2782 /***********************************************************************
2783 * GetSystemMetricsForDpi (USER32.@)
2785 INT WINAPI GetSystemMetricsForDpi( INT index, UINT dpi )
2787 NONCLIENTMETRICSW ncm;
2788 ICONMETRICSW im;
2789 UINT ret;
2790 HDC hdc;
2792 /* some metrics are dynamic */
2793 switch (index)
2795 case SM_CXVSCROLL:
2796 case SM_CYHSCROLL:
2797 get_entry_dpi( &entry_SCROLLWIDTH, 0, &ret, dpi );
2798 return max( ret, 8 );
2799 case SM_CYCAPTION:
2800 ncm.cbSize = sizeof(ncm);
2801 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2802 return ncm.iCaptionHeight + 1;
2803 case SM_CYVTHUMB:
2804 case SM_CXHTHUMB:
2805 case SM_CYVSCROLL:
2806 case SM_CXHSCROLL:
2807 get_entry_dpi( &entry_SCROLLHEIGHT, 0, &ret, dpi );
2808 return max( ret, 8 );
2809 case SM_CXICON:
2810 case SM_CYICON:
2811 return map_to_dpi( 32, dpi );
2812 case SM_CXCURSOR:
2813 case SM_CYCURSOR:
2814 ret = map_to_dpi( 32, dpi );
2815 if (ret >= 64) return 64;
2816 if (ret >= 48) return 48;
2817 return 32;
2818 case SM_CYMENU:
2819 ncm.cbSize = sizeof(ncm);
2820 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2821 return ncm.iMenuHeight + 1;
2822 case SM_CXSIZE:
2823 get_entry_dpi( &entry_CAPTIONWIDTH, 0, &ret, dpi );
2824 return max( ret, 8 );
2825 case SM_CYSIZE:
2826 ncm.cbSize = sizeof(ncm);
2827 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2828 return ncm.iCaptionHeight;
2829 case SM_CXFRAME:
2830 get_entry_dpi( &entry_BORDER, 0, &ret, dpi );
2831 ret = max( ret, 1 );
2832 return GetSystemMetricsForDpi( SM_CXDLGFRAME, dpi ) + ret;
2833 case SM_CYFRAME:
2834 get_entry_dpi( &entry_BORDER, 0, &ret, dpi );
2835 ret = max( ret, 1 );
2836 return GetSystemMetricsForDpi( SM_CYDLGFRAME, dpi ) + ret;
2837 case SM_CXICONSPACING:
2838 im.cbSize = sizeof(im);
2839 SystemParametersInfoForDpi( SPI_GETICONMETRICS, sizeof(im), &im, 0, dpi );
2840 return im.iHorzSpacing;
2841 case SM_CYICONSPACING:
2842 im.cbSize = sizeof(im);
2843 SystemParametersInfoForDpi( SPI_GETICONMETRICS, sizeof(im), &im, 0, dpi );
2844 return im.iVertSpacing;
2845 case SM_CXSMICON:
2846 case SM_CYSMICON:
2847 return map_to_dpi( 16, dpi ) & ~1;
2848 case SM_CYSMCAPTION:
2849 ncm.cbSize = sizeof(ncm);
2850 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2851 return ncm.iSmCaptionHeight + 1;
2852 case SM_CXSMSIZE:
2853 get_entry_dpi( &entry_SMCAPTIONWIDTH, 0, &ret, dpi );
2854 return ret;
2855 case SM_CYSMSIZE:
2856 ncm.cbSize = sizeof(ncm);
2857 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2858 return ncm.iSmCaptionHeight;
2859 case SM_CXMENUSIZE:
2860 get_entry_dpi( &entry_MENUWIDTH, 0, &ret, dpi );
2861 return ret;
2862 case SM_CYMENUSIZE:
2863 ncm.cbSize = sizeof(ncm);
2864 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2865 return ncm.iMenuHeight;
2866 case SM_CXMENUCHECK:
2867 case SM_CYMENUCHECK:
2869 TEXTMETRICW tm;
2870 ncm.cbSize = sizeof(ncm);
2871 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
2872 hdc = get_display_dc();
2873 get_text_metr_size( hdc, &ncm.lfMenuFont, &tm, NULL);
2874 release_display_dc( hdc );
2875 return tm.tmHeight <= 0 ? 13 : ((tm.tmHeight + tm.tmExternalLeading - 1) | 1);
2877 default:
2878 return GetSystemMetrics( index );
2883 /***********************************************************************
2884 * SwapMouseButton (USER32.@)
2885 * Reverse or restore the meaning of the left and right mouse buttons
2886 * fSwap [I ] TRUE - reverse, FALSE - original
2887 * RETURN
2888 * previous state
2890 BOOL WINAPI SwapMouseButton( BOOL fSwap )
2892 BOOL prev = GetSystemMetrics(SM_SWAPBUTTON);
2893 SystemParametersInfoW(SPI_SETMOUSEBUTTONSWAP, fSwap, 0, 0);
2894 return prev;
2898 /**********************************************************************
2899 * SetDoubleClickTime (USER32.@)
2901 BOOL WINAPI SetDoubleClickTime( UINT interval )
2903 return SystemParametersInfoW(SPI_SETDOUBLECLICKTIME, interval, 0, 0);
2907 /**********************************************************************
2908 * GetDoubleClickTime (USER32.@)
2910 UINT WINAPI GetDoubleClickTime(void)
2912 UINT time = 0;
2914 get_entry( &entry_DOUBLECLICKTIME, 0, &time );
2915 if (!time) time = 500;
2916 return time;
2920 /*************************************************************************
2921 * GetSysColor (USER32.@)
2923 COLORREF WINAPI DECLSPEC_HOTPATCH GetSysColor( INT nIndex )
2925 COLORREF ret = 0;
2927 if (nIndex >= 0 && nIndex < ARRAY_SIZE( system_colors ))
2928 get_entry( &system_colors[nIndex], 0, &ret );
2929 return ret;
2933 /*************************************************************************
2934 * SetSysColors (USER32.@)
2936 BOOL WINAPI SetSysColors( INT count, const INT *colors, const COLORREF *values )
2938 int i;
2940 if (IS_INTRESOURCE(colors)) return FALSE; /* stupid app passes a color instead of an array */
2942 for (i = 0; i < count; i++)
2943 if (colors[i] >= 0 && colors[i] <= ARRAY_SIZE( system_colors ))
2944 set_entry( &system_colors[colors[i]], values[i], 0, 0 );
2946 /* Send WM_SYSCOLORCHANGE message to all windows */
2948 SendMessageTimeoutW( HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0, SMTO_ABORTIFHUNG, 2000, NULL );
2950 /* Repaint affected portions of all visible windows */
2952 RedrawWindow( 0, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN );
2953 return TRUE;
2957 /*************************************************************************
2958 * SetSysColorsTemp (USER32.@)
2960 DWORD_PTR WINAPI SetSysColorsTemp( const COLORREF *pPens, const HBRUSH *pBrushes, DWORD_PTR n)
2962 FIXME( "no longer supported\n" );
2963 return FALSE;
2967 /***********************************************************************
2968 * GetSysColorBrush (USER32.@)
2970 HBRUSH WINAPI DECLSPEC_HOTPATCH GetSysColorBrush( INT index )
2972 if (index < 0 || index >= ARRAY_SIZE( system_colors )) return 0;
2974 if (!system_colors[index].brush)
2976 HBRUSH brush = CreateSolidBrush( GetSysColor( index ));
2977 __wine_make_gdi_object_system( brush, TRUE );
2978 if (InterlockedCompareExchangePointer( (void **)&system_colors[index].brush, brush, 0 ))
2980 __wine_make_gdi_object_system( brush, FALSE );
2981 DeleteObject( brush );
2984 return system_colors[index].brush;
2988 /***********************************************************************
2989 * SYSCOLOR_GetPen
2991 HPEN SYSCOLOR_GetPen( INT index )
2993 /* We can assert here, because this function is internal to Wine */
2994 assert (0 <= index && index < ARRAY_SIZE( system_colors ));
2996 if (!system_colors[index].pen)
2998 HPEN pen = CreatePen( PS_SOLID, 1, GetSysColor( index ));
2999 __wine_make_gdi_object_system( pen, TRUE );
3000 if (InterlockedCompareExchangePointer( (void **)&system_colors[index].pen, pen, 0 ))
3002 __wine_make_gdi_object_system( pen, FALSE );
3003 DeleteObject( pen );
3006 return system_colors[index].pen;
3010 /***********************************************************************
3011 * SYSCOLOR_Get55AABrush
3013 HBRUSH SYSCOLOR_Get55AABrush(void)
3015 static const WORD pattern[] = { 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa };
3016 static HBRUSH brush_55aa;
3018 if (!brush_55aa)
3020 HBITMAP bitmap = CreateBitmap( 8, 8, 1, 1, pattern );
3021 HBRUSH brush = CreatePatternBrush( bitmap );
3022 DeleteObject( bitmap );
3023 __wine_make_gdi_object_system( brush, TRUE );
3024 if (InterlockedCompareExchangePointer( (void **)&brush_55aa, brush, 0 ))
3026 __wine_make_gdi_object_system( brush, FALSE );
3027 DeleteObject( brush );
3030 return brush_55aa;
3033 /***********************************************************************
3034 * ChangeDisplaySettingsA (USER32.@)
3036 LONG WINAPI ChangeDisplaySettingsA( LPDEVMODEA devmode, DWORD flags )
3038 if (devmode) devmode->dmDriverExtra = 0;
3040 return ChangeDisplaySettingsExA(NULL,devmode,NULL,flags,NULL);
3044 /***********************************************************************
3045 * ChangeDisplaySettingsW (USER32.@)
3047 LONG WINAPI ChangeDisplaySettingsW( LPDEVMODEW devmode, DWORD flags )
3049 if (devmode) devmode->dmDriverExtra = 0;
3051 return ChangeDisplaySettingsExW(NULL,devmode,NULL,flags,NULL);
3055 /***********************************************************************
3056 * ChangeDisplaySettingsExA (USER32.@)
3058 LONG WINAPI ChangeDisplaySettingsExA( LPCSTR devname, LPDEVMODEA devmode, HWND hwnd,
3059 DWORD flags, LPVOID lparam )
3061 LONG ret;
3062 UNICODE_STRING nameW;
3064 if (devname) RtlCreateUnicodeStringFromAsciiz(&nameW, devname);
3065 else nameW.Buffer = NULL;
3067 if (devmode)
3069 DEVMODEW *devmodeW;
3071 devmodeW = GdiConvertToDevmodeW(devmode);
3072 if (devmodeW)
3074 ret = ChangeDisplaySettingsExW(nameW.Buffer, devmodeW, hwnd, flags, lparam);
3075 HeapFree(GetProcessHeap(), 0, devmodeW);
3077 else
3078 ret = DISP_CHANGE_SUCCESSFUL;
3080 else
3082 ret = ChangeDisplaySettingsExW(nameW.Buffer, NULL, hwnd, flags, lparam);
3085 if (devname) RtlFreeUnicodeString(&nameW);
3086 return ret;
3089 #define _X_FIELD(prefix, bits) \
3090 if ((fields) & prefix##_##bits) \
3092 p += sprintf(p, "%s%s", first ? "" : ",", #bits); \
3093 first = FALSE; \
3096 static const CHAR *_CDS_flags(DWORD fields)
3098 BOOL first = TRUE;
3099 CHAR buf[128];
3100 CHAR *p = buf;
3102 _X_FIELD(CDS, UPDATEREGISTRY)
3103 _X_FIELD(CDS, TEST)
3104 _X_FIELD(CDS, FULLSCREEN)
3105 _X_FIELD(CDS, GLOBAL)
3106 _X_FIELD(CDS, SET_PRIMARY)
3107 _X_FIELD(CDS, VIDEOPARAMETERS)
3108 _X_FIELD(CDS, ENABLE_UNSAFE_MODES)
3109 _X_FIELD(CDS, DISABLE_UNSAFE_MODES)
3110 _X_FIELD(CDS, RESET)
3111 _X_FIELD(CDS, RESET_EX)
3112 _X_FIELD(CDS, NORESET)
3114 *p = 0;
3115 return wine_dbg_sprintf("%s", buf);
3118 static const CHAR *_DM_fields(DWORD fields)
3120 BOOL first = TRUE;
3121 CHAR buf[128];
3122 CHAR *p = buf;
3124 _X_FIELD(DM, BITSPERPEL)
3125 _X_FIELD(DM, PELSWIDTH)
3126 _X_FIELD(DM, PELSHEIGHT)
3127 _X_FIELD(DM, DISPLAYFLAGS)
3128 _X_FIELD(DM, DISPLAYFREQUENCY)
3129 _X_FIELD(DM, POSITION)
3130 _X_FIELD(DM, DISPLAYORIENTATION)
3132 *p = 0;
3133 return wine_dbg_sprintf("%s", buf);
3136 #undef _X_FIELD
3138 static void trace_devmode(const DEVMODEW *devmode)
3140 TRACE("dmFields=%s ", _DM_fields(devmode->dmFields));
3141 if (devmode->dmFields & DM_BITSPERPEL)
3142 TRACE("dmBitsPerPel=%u ", devmode->dmBitsPerPel);
3143 if (devmode->dmFields & DM_PELSWIDTH)
3144 TRACE("dmPelsWidth=%u ", devmode->dmPelsWidth);
3145 if (devmode->dmFields & DM_PELSHEIGHT)
3146 TRACE("dmPelsHeight=%u ", devmode->dmPelsHeight);
3147 if (devmode->dmFields & DM_DISPLAYFREQUENCY)
3148 TRACE("dmDisplayFrequency=%u ", devmode->dmDisplayFrequency);
3149 if (devmode->dmFields & DM_POSITION)
3150 TRACE("dmPosition=(%d,%d) ", devmode->u1.s2.dmPosition.x, devmode->u1.s2.dmPosition.y);
3151 if (devmode->dmFields & DM_DISPLAYFLAGS)
3152 TRACE("dmDisplayFlags=%#x ", devmode->u2.dmDisplayFlags);
3153 if (devmode->dmFields & DM_DISPLAYORIENTATION)
3154 TRACE("dmDisplayOrientation=%u ", devmode->u1.s2.dmDisplayOrientation);
3155 TRACE("\n");
3158 static BOOL is_detached_mode(const DEVMODEW *mode)
3160 return mode->dmFields & DM_POSITION &&
3161 mode->dmFields & DM_PELSWIDTH &&
3162 mode->dmFields & DM_PELSHEIGHT &&
3163 mode->dmPelsWidth == 0 &&
3164 mode->dmPelsHeight == 0;
3167 /***********************************************************************
3168 * ChangeDisplaySettingsExW (USER32.@)
3170 LONG WINAPI ChangeDisplaySettingsExW( LPCWSTR devname, LPDEVMODEW devmode, HWND hwnd,
3171 DWORD flags, LPVOID lparam )
3173 WCHAR primary_adapter[CCHDEVICENAME];
3174 BOOL def_mode = TRUE;
3175 DEVMODEW dm;
3176 LONG ret;
3178 TRACE("%s %p %p %#x %p\n", debugstr_w(devname), devmode, hwnd, flags, lparam);
3179 TRACE("flags=%s\n", _CDS_flags(flags));
3181 if (!devname && !devmode)
3183 ret = USER_Driver->pChangeDisplaySettingsEx(NULL, NULL, hwnd, flags, lparam);
3184 if (ret != DISP_CHANGE_SUCCESSFUL)
3185 ERR("Restoring all displays to their registry settings returned %d.\n", ret);
3186 return ret;
3189 if (!devname && devmode)
3191 if (!get_primary_adapter(primary_adapter))
3192 return DISP_CHANGE_FAILED;
3194 devname = primary_adapter;
3197 if (!is_valid_adapter_name(devname))
3199 ERR("Invalid device name %s.\n", wine_dbgstr_w(devname));
3200 return DISP_CHANGE_BADPARAM;
3203 if (devmode)
3205 trace_devmode(devmode);
3207 if (devmode->dmSize < FIELD_OFFSET(DEVMODEW, dmICMMethod))
3208 return DISP_CHANGE_BADMODE;
3210 if (is_detached_mode(devmode) ||
3211 ((devmode->dmFields & DM_BITSPERPEL) && devmode->dmBitsPerPel) ||
3212 ((devmode->dmFields & DM_PELSWIDTH) && devmode->dmPelsWidth) ||
3213 ((devmode->dmFields & DM_PELSHEIGHT) && devmode->dmPelsHeight) ||
3214 ((devmode->dmFields & DM_DISPLAYFREQUENCY) && devmode->dmDisplayFrequency))
3215 def_mode = FALSE;
3218 if (def_mode)
3220 memset(&dm, 0, sizeof(dm));
3221 dm.dmSize = sizeof(dm);
3222 if (!EnumDisplaySettingsExW(devname, ENUM_REGISTRY_SETTINGS, &dm, 0))
3224 ERR("Default mode not found!\n");
3225 return DISP_CHANGE_BADMODE;
3228 TRACE("Return to original display mode\n");
3229 devmode = &dm;
3232 if ((devmode->dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != (DM_PELSWIDTH | DM_PELSHEIGHT))
3234 WARN("devmode doesn't specify the resolution: %#x\n", devmode->dmFields);
3235 return DISP_CHANGE_BADMODE;
3238 if (!is_detached_mode(devmode) && (!devmode->dmPelsWidth || !devmode->dmPelsHeight))
3240 memset(&dm, 0, sizeof(dm));
3241 dm.dmSize = sizeof(dm);
3242 if (!EnumDisplaySettingsExW(devname, ENUM_CURRENT_SETTINGS, &dm, 0))
3244 ERR("Current mode not found!\n");
3245 return DISP_CHANGE_BADMODE;
3248 if (!devmode->dmPelsWidth)
3249 devmode->dmPelsWidth = dm.dmPelsWidth;
3250 if (!devmode->dmPelsHeight)
3251 devmode->dmPelsHeight = dm.dmPelsHeight;
3254 ret = USER_Driver->pChangeDisplaySettingsEx(devname, devmode, hwnd, flags, lparam);
3255 if (ret != DISP_CHANGE_SUCCESSFUL)
3256 ERR("Changing %s display settings returned %d.\n", wine_dbgstr_w(devname), ret);
3257 return ret;
3261 /***********************************************************************
3262 * EnumDisplaySettingsW (USER32.@)
3264 * RETURNS
3265 * TRUE if nth setting exists found (described in the LPDEVMODEW struct)
3266 * FALSE if we do not have the nth setting
3268 BOOL WINAPI EnumDisplaySettingsW( LPCWSTR name, DWORD n, LPDEVMODEW devmode )
3270 return EnumDisplaySettingsExW(name, n, devmode, 0);
3274 /***********************************************************************
3275 * EnumDisplaySettingsA (USER32.@)
3277 BOOL WINAPI EnumDisplaySettingsA(LPCSTR name,DWORD n,LPDEVMODEA devmode)
3279 return EnumDisplaySettingsExA(name, n, devmode, 0);
3283 /***********************************************************************
3284 * EnumDisplaySettingsExA (USER32.@)
3286 BOOL WINAPI EnumDisplaySettingsExA(LPCSTR lpszDeviceName, DWORD iModeNum,
3287 LPDEVMODEA lpDevMode, DWORD dwFlags)
3289 DEVMODEW devmodeW;
3290 BOOL ret;
3291 UNICODE_STRING nameW;
3293 if (lpszDeviceName) RtlCreateUnicodeStringFromAsciiz(&nameW, lpszDeviceName);
3294 else nameW.Buffer = NULL;
3296 memset(&devmodeW, 0, sizeof(devmodeW));
3297 devmodeW.dmSize = sizeof(devmodeW);
3298 ret = EnumDisplaySettingsExW(nameW.Buffer,iModeNum,&devmodeW,dwFlags);
3299 if (ret)
3301 lpDevMode->dmSize = FIELD_OFFSET(DEVMODEA, dmICMMethod);
3302 lpDevMode->dmSpecVersion = devmodeW.dmSpecVersion;
3303 lpDevMode->dmDriverVersion = devmodeW.dmDriverVersion;
3304 WideCharToMultiByte(CP_ACP, 0, devmodeW.dmDeviceName, -1,
3305 (LPSTR)lpDevMode->dmDeviceName, CCHDEVICENAME, NULL, NULL);
3306 lpDevMode->dmDriverExtra = 0; /* FIXME */
3307 lpDevMode->dmBitsPerPel = devmodeW.dmBitsPerPel;
3308 lpDevMode->dmPelsHeight = devmodeW.dmPelsHeight;
3309 lpDevMode->dmPelsWidth = devmodeW.dmPelsWidth;
3310 lpDevMode->u2.dmDisplayFlags = devmodeW.u2.dmDisplayFlags;
3311 lpDevMode->dmDisplayFrequency = devmodeW.dmDisplayFrequency;
3312 lpDevMode->dmFields = devmodeW.dmFields;
3314 lpDevMode->u1.s2.dmPosition.x = devmodeW.u1.s2.dmPosition.x;
3315 lpDevMode->u1.s2.dmPosition.y = devmodeW.u1.s2.dmPosition.y;
3316 lpDevMode->u1.s2.dmDisplayOrientation = devmodeW.u1.s2.dmDisplayOrientation;
3317 lpDevMode->u1.s2.dmDisplayFixedOutput = devmodeW.u1.s2.dmDisplayFixedOutput;
3319 if (lpszDeviceName) RtlFreeUnicodeString(&nameW);
3320 return ret;
3324 /***********************************************************************
3325 * EnumDisplaySettingsExW (USER32.@)
3327 BOOL WINAPI EnumDisplaySettingsExW(LPCWSTR lpszDeviceName, DWORD iModeNum,
3328 LPDEVMODEW lpDevMode, DWORD dwFlags)
3330 WCHAR primary_adapter[CCHDEVICENAME];
3331 BOOL ret;
3333 TRACE("%s %#x %p %#x\n", wine_dbgstr_w(lpszDeviceName), iModeNum, lpDevMode, dwFlags);
3335 if (!lpszDeviceName)
3337 if (!get_primary_adapter(primary_adapter))
3338 return FALSE;
3340 lpszDeviceName = primary_adapter;
3343 if (!is_valid_adapter_name(lpszDeviceName))
3345 ERR("Invalid device name %s.\n", wine_dbgstr_w(lpszDeviceName));
3346 return FALSE;
3349 ret = USER_Driver->pEnumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, dwFlags);
3350 if (ret)
3351 TRACE("device:%s mode index:%#x position:(%d,%d) resolution:%ux%u frequency:%uHz "
3352 "depth:%ubits orientation:%#x.\n", wine_dbgstr_w(lpszDeviceName), iModeNum,
3353 lpDevMode->u1.s2.dmPosition.x, lpDevMode->u1.s2.dmPosition.y, lpDevMode->dmPelsWidth,
3354 lpDevMode->dmPelsHeight, lpDevMode->dmDisplayFrequency, lpDevMode->dmBitsPerPel,
3355 lpDevMode->u1.s2.dmDisplayOrientation);
3356 else
3357 WARN("Failed to query %s display settings.\n", wine_dbgstr_w(lpszDeviceName));
3358 return ret;
3362 /**********************************************************************
3363 * get_monitor_dpi
3365 UINT get_monitor_dpi( HMONITOR monitor )
3367 /* FIXME: use the monitor DPI instead */
3368 return system_dpi;
3371 /**********************************************************************
3372 * get_win_monitor_dpi
3374 UINT get_win_monitor_dpi( HWND hwnd )
3376 /* FIXME: use the monitor DPI instead */
3377 return system_dpi;
3380 /**********************************************************************
3381 * get_thread_dpi
3383 UINT get_thread_dpi(void)
3385 switch (GetAwarenessFromDpiAwarenessContext( GetThreadDpiAwarenessContext() ))
3387 case DPI_AWARENESS_UNAWARE: return USER_DEFAULT_SCREEN_DPI;
3388 case DPI_AWARENESS_SYSTEM_AWARE: return system_dpi;
3389 default: return 0; /* no scaling */
3393 /**********************************************************************
3394 * map_dpi_point
3396 POINT map_dpi_point( POINT pt, UINT dpi_from, UINT dpi_to )
3398 if (dpi_from && dpi_to && dpi_from != dpi_to)
3400 pt.x = MulDiv( pt.x, dpi_to, dpi_from );
3401 pt.y = MulDiv( pt.y, dpi_to, dpi_from );
3403 return pt;
3406 /**********************************************************************
3407 * point_win_to_phys_dpi
3409 POINT point_win_to_phys_dpi( HWND hwnd, POINT pt )
3411 return map_dpi_point( pt, GetDpiForWindow( hwnd ), get_win_monitor_dpi( hwnd ) );
3414 /**********************************************************************
3415 * point_phys_to_win_dpi
3417 POINT point_phys_to_win_dpi( HWND hwnd, POINT pt )
3419 return map_dpi_point( pt, get_win_monitor_dpi( hwnd ), GetDpiForWindow( hwnd ));
3422 /**********************************************************************
3423 * point_win_to_thread_dpi
3425 POINT point_win_to_thread_dpi( HWND hwnd, POINT pt )
3427 UINT dpi = get_thread_dpi();
3428 if (!dpi) dpi = get_win_monitor_dpi( hwnd );
3429 return map_dpi_point( pt, GetDpiForWindow( hwnd ), dpi );
3432 /**********************************************************************
3433 * point_thread_to_win_dpi
3435 POINT point_thread_to_win_dpi( HWND hwnd, POINT pt )
3437 UINT dpi = get_thread_dpi();
3438 if (!dpi) dpi = get_win_monitor_dpi( hwnd );
3439 return map_dpi_point( pt, dpi, GetDpiForWindow( hwnd ));
3442 /**********************************************************************
3443 * map_dpi_rect
3445 RECT map_dpi_rect( RECT rect, UINT dpi_from, UINT dpi_to )
3447 if (dpi_from && dpi_to && dpi_from != dpi_to)
3449 rect.left = MulDiv( rect.left, dpi_to, dpi_from );
3450 rect.top = MulDiv( rect.top, dpi_to, dpi_from );
3451 rect.right = MulDiv( rect.right, dpi_to, dpi_from );
3452 rect.bottom = MulDiv( rect.bottom, dpi_to, dpi_from );
3454 return rect;
3457 /**********************************************************************
3458 * rect_win_to_thread_dpi
3460 RECT rect_win_to_thread_dpi( HWND hwnd, RECT rect )
3462 UINT dpi = get_thread_dpi();
3463 if (!dpi) dpi = get_win_monitor_dpi( hwnd );
3464 return map_dpi_rect( rect, GetDpiForWindow( hwnd ), dpi );
3467 /**********************************************************************
3468 * rect_thread_to_win_dpi
3470 RECT rect_thread_to_win_dpi( HWND hwnd, RECT rect )
3472 UINT dpi = get_thread_dpi();
3473 if (!dpi) dpi = get_win_monitor_dpi( hwnd );
3474 return map_dpi_rect( rect, dpi, GetDpiForWindow( hwnd ) );
3477 /**********************************************************************
3478 * SetProcessDpiAwarenessContext (USER32.@)
3480 BOOL WINAPI SetProcessDpiAwarenessContext( DPI_AWARENESS_CONTEXT context )
3482 DPI_AWARENESS val = GetAwarenessFromDpiAwarenessContext( context );
3484 if (val == DPI_AWARENESS_INVALID)
3486 SetLastError( ERROR_INVALID_PARAMETER );
3487 return FALSE;
3489 val |= 0x10; /* avoid 0 value */
3490 if (InterlockedCompareExchange( &dpi_awareness, val, 0 ))
3492 SetLastError( ERROR_ACCESS_DENIED );
3493 return FALSE;
3495 TRACE( "set to %p\n", context );
3496 return TRUE;
3499 /**********************************************************************
3500 * GetProcessDpiAwarenessInternal (USER32.@)
3502 BOOL WINAPI GetProcessDpiAwarenessInternal( HANDLE process, DPI_AWARENESS *awareness )
3504 if (process && process != GetCurrentProcess())
3506 WARN( "not supported on other process %p\n", process );
3507 *awareness = DPI_AWARENESS_UNAWARE;
3509 else *awareness = dpi_awareness & 3;
3510 return TRUE;
3513 /**********************************************************************
3514 * SetProcessDpiAwarenessInternal (USER32.@)
3516 BOOL WINAPI SetProcessDpiAwarenessInternal( DPI_AWARENESS awareness )
3518 static const DPI_AWARENESS_CONTEXT contexts[3] = { DPI_AWARENESS_CONTEXT_UNAWARE,
3519 DPI_AWARENESS_CONTEXT_SYSTEM_AWARE,
3520 DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE };
3522 if (awareness < DPI_AWARENESS_UNAWARE || awareness > DPI_AWARENESS_PER_MONITOR_AWARE)
3524 SetLastError( ERROR_INVALID_PARAMETER );
3525 return FALSE;
3527 return SetProcessDpiAwarenessContext( contexts[awareness] );
3530 /***********************************************************************
3531 * AreDpiAwarenessContextsEqual (USER32.@)
3533 BOOL WINAPI AreDpiAwarenessContextsEqual( DPI_AWARENESS_CONTEXT ctx1, DPI_AWARENESS_CONTEXT ctx2 )
3535 DPI_AWARENESS aware1 = GetAwarenessFromDpiAwarenessContext( ctx1 );
3536 DPI_AWARENESS aware2 = GetAwarenessFromDpiAwarenessContext( ctx2 );
3537 return aware1 != DPI_AWARENESS_INVALID && aware1 == aware2;
3540 /***********************************************************************
3541 * GetAwarenessFromDpiAwarenessContext (USER32.@)
3543 DPI_AWARENESS WINAPI GetAwarenessFromDpiAwarenessContext( DPI_AWARENESS_CONTEXT context )
3545 switch ((ULONG_PTR)context)
3547 case 0x10:
3548 case 0x11:
3549 case 0x12:
3550 case 0x80000010:
3551 case 0x80000011:
3552 case 0x80000012:
3553 return (ULONG_PTR)context & 3;
3554 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE:
3555 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE:
3556 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE:
3557 return ~(ULONG_PTR)context;
3558 default:
3559 return DPI_AWARENESS_INVALID;
3563 /***********************************************************************
3564 * IsValidDpiAwarenessContext (USER32.@)
3566 BOOL WINAPI IsValidDpiAwarenessContext( DPI_AWARENESS_CONTEXT context )
3568 return GetAwarenessFromDpiAwarenessContext( context ) != DPI_AWARENESS_INVALID;
3571 /***********************************************************************
3572 * SetProcessDPIAware (USER32.@)
3574 BOOL WINAPI SetProcessDPIAware(void)
3576 TRACE("\n");
3577 InterlockedCompareExchange( &dpi_awareness, 0x11, 0 );
3578 return TRUE;
3581 /***********************************************************************
3582 * IsProcessDPIAware (USER32.@)
3584 BOOL WINAPI IsProcessDPIAware(void)
3586 return GetAwarenessFromDpiAwarenessContext( GetThreadDpiAwarenessContext() ) != DPI_AWARENESS_UNAWARE;
3589 /**********************************************************************
3590 * EnableNonClientDpiScaling (USER32.@)
3592 BOOL WINAPI EnableNonClientDpiScaling( HWND hwnd )
3594 FIXME("(%p): stub\n", hwnd);
3595 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
3596 return FALSE;
3599 /***********************************************************************
3600 * GetDpiForSystem (USER32.@)
3602 UINT WINAPI GetDpiForSystem(void)
3604 if (!IsProcessDPIAware()) return USER_DEFAULT_SCREEN_DPI;
3605 return system_dpi;
3608 /***********************************************************************
3609 * GetDpiForMonitorInternal (USER32.@)
3611 BOOL WINAPI GetDpiForMonitorInternal( HMONITOR monitor, UINT type, UINT *x, UINT *y )
3613 if (type > 2)
3615 SetLastError( ERROR_BAD_ARGUMENTS );
3616 return FALSE;
3618 if (!x || !y)
3620 SetLastError( ERROR_INVALID_ADDRESS );
3621 return FALSE;
3623 switch (GetAwarenessFromDpiAwarenessContext( GetThreadDpiAwarenessContext() ))
3625 case DPI_AWARENESS_UNAWARE: *x = *y = USER_DEFAULT_SCREEN_DPI; break;
3626 case DPI_AWARENESS_SYSTEM_AWARE: *x = *y = system_dpi; break;
3627 default: *x = *y = get_monitor_dpi( monitor ); break;
3629 return TRUE;
3632 /**********************************************************************
3633 * GetThreadDpiAwarenessContext (USER32.@)
3635 DPI_AWARENESS_CONTEXT WINAPI GetThreadDpiAwarenessContext(void)
3637 struct user_thread_info *info = get_user_thread_info();
3639 if (info->dpi_awareness) return ULongToHandle( info->dpi_awareness );
3640 if (dpi_awareness) return ULongToHandle( dpi_awareness );
3641 return ULongToHandle( 0x10 | default_awareness );
3644 /**********************************************************************
3645 * SetThreadDpiAwarenessContext (USER32.@)
3647 DPI_AWARENESS_CONTEXT WINAPI SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT context )
3649 struct user_thread_info *info = get_user_thread_info();
3650 DPI_AWARENESS prev, val = GetAwarenessFromDpiAwarenessContext( context );
3652 if (val == DPI_AWARENESS_INVALID)
3654 SetLastError( ERROR_INVALID_PARAMETER );
3655 return 0;
3657 if (!(prev = info->dpi_awareness))
3659 prev = dpi_awareness;
3660 if (!prev) prev = 0x10 | DPI_AWARENESS_UNAWARE;
3661 prev |= 0x80000000; /* restore to process default */
3663 if (((ULONG_PTR)context & ~(ULONG_PTR)0x13) == 0x80000000) info->dpi_awareness = 0;
3664 else info->dpi_awareness = val | 0x10;
3665 return ULongToHandle( prev );
3668 /**********************************************************************
3669 * LogicalToPhysicalPointForPerMonitorDPI (USER32.@)
3671 BOOL WINAPI LogicalToPhysicalPointForPerMonitorDPI( HWND hwnd, POINT *pt )
3673 RECT rect;
3675 if (!GetWindowRect( hwnd, &rect )) return FALSE;
3676 if (pt->x < rect.left || pt->y < rect.top || pt->x > rect.right || pt->y > rect.bottom) return FALSE;
3677 *pt = point_win_to_phys_dpi( hwnd, *pt );
3678 return TRUE;
3681 /**********************************************************************
3682 * PhysicalToLogicalPointForPerMonitorDPI (USER32.@)
3684 BOOL WINAPI PhysicalToLogicalPointForPerMonitorDPI( HWND hwnd, POINT *pt )
3686 DPI_AWARENESS_CONTEXT context;
3687 RECT rect;
3688 BOOL ret = FALSE;
3690 context = SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
3691 if (GetWindowRect( hwnd, &rect ) &&
3692 pt->x >= rect.left && pt->y >= rect.top && pt->x <= rect.right && pt->y <= rect.bottom)
3694 *pt = point_phys_to_win_dpi( hwnd, *pt );
3695 ret = TRUE;
3697 SetThreadDpiAwarenessContext( context );
3698 return ret;
3701 struct monitor_enum_info
3703 RECT rect;
3704 UINT max_area;
3705 UINT min_distance;
3706 HMONITOR primary;
3707 HMONITOR nearest;
3708 HMONITOR ret;
3711 /* helper callback for MonitorFromRect */
3712 static BOOL CALLBACK monitor_enum( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
3714 struct monitor_enum_info *info = (struct monitor_enum_info *)lp;
3715 RECT intersect;
3717 if (IntersectRect( &intersect, rect, &info->rect ))
3719 /* check for larger intersecting area */
3720 UINT area = (intersect.right - intersect.left) * (intersect.bottom - intersect.top);
3721 if (area > info->max_area)
3723 info->max_area = area;
3724 info->ret = monitor;
3727 else if (!info->max_area) /* if not intersecting, check for min distance */
3729 UINT distance;
3730 UINT x, y;
3732 if (info->rect.right <= rect->left) x = rect->left - info->rect.right;
3733 else if (rect->right <= info->rect.left) x = info->rect.left - rect->right;
3734 else x = 0;
3735 if (info->rect.bottom <= rect->top) y = rect->top - info->rect.bottom;
3736 else if (rect->bottom <= info->rect.top) y = info->rect.top - rect->bottom;
3737 else y = 0;
3738 distance = x * x + y * y;
3739 if (distance < info->min_distance)
3741 info->min_distance = distance;
3742 info->nearest = monitor;
3745 if (!info->primary)
3747 MONITORINFO mon_info;
3748 mon_info.cbSize = sizeof(mon_info);
3749 GetMonitorInfoW( monitor, &mon_info );
3750 if (mon_info.dwFlags & MONITORINFOF_PRIMARY) info->primary = monitor;
3752 return TRUE;
3755 /***********************************************************************
3756 * MonitorFromRect (USER32.@)
3758 HMONITOR WINAPI MonitorFromRect( const RECT *rect, DWORD flags )
3760 struct monitor_enum_info info;
3762 info.rect = *rect;
3763 info.max_area = 0;
3764 info.min_distance = ~0u;
3765 info.primary = 0;
3766 info.nearest = 0;
3767 info.ret = 0;
3769 if (IsRectEmpty(&info.rect))
3771 info.rect.right = info.rect.left + 1;
3772 info.rect.bottom = info.rect.top + 1;
3775 if (!EnumDisplayMonitors( 0, NULL, monitor_enum, (LPARAM)&info )) return 0;
3776 if (!info.ret)
3778 if (flags & MONITOR_DEFAULTTOPRIMARY) info.ret = info.primary;
3779 else if (flags & MONITOR_DEFAULTTONEAREST) info.ret = info.nearest;
3782 TRACE( "%s flags %x returning %p\n", wine_dbgstr_rect(rect), flags, info.ret );
3783 return info.ret;
3786 /***********************************************************************
3787 * MonitorFromPoint (USER32.@)
3789 HMONITOR WINAPI MonitorFromPoint( POINT pt, DWORD flags )
3791 RECT rect;
3793 SetRect( &rect, pt.x, pt.y, pt.x + 1, pt.y + 1 );
3794 return MonitorFromRect( &rect, flags );
3797 /***********************************************************************
3798 * MonitorFromWindow (USER32.@)
3800 HMONITOR WINAPI MonitorFromWindow(HWND hWnd, DWORD dwFlags)
3802 RECT rect;
3803 WINDOWPLACEMENT wp;
3805 TRACE("(%p, 0x%08x)\n", hWnd, dwFlags);
3807 wp.length = sizeof(wp);
3808 if (IsIconic(hWnd) && GetWindowPlacement(hWnd, &wp))
3809 return MonitorFromRect( &wp.rcNormalPosition, dwFlags );
3811 if (GetWindowRect( hWnd, &rect ))
3812 return MonitorFromRect( &rect, dwFlags );
3814 if (!(dwFlags & (MONITOR_DEFAULTTOPRIMARY|MONITOR_DEFAULTTONEAREST))) return 0;
3815 /* retrieve the primary */
3816 SetRect( &rect, 0, 0, 1, 1 );
3817 return MonitorFromRect( &rect, dwFlags );
3820 /* Return FALSE on failure and TRUE on success */
3821 static BOOL update_display_cache(void)
3823 struct display_device device, *adapter, *adapter2, *monitor, *monitor2;
3824 DWORD adapter_idx, monitor_idx;
3825 struct list *monitor_list;
3826 FILETIME filetime = {0};
3827 HANDLE mutex = NULL;
3828 BOOL ret = FALSE;
3830 /* Update display cache from SetupAPI if it's outdated */
3831 wait_graphics_driver_ready();
3833 if (!video_key && RegOpenKeyW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", &video_key ))
3834 return FALSE;
3835 if (RegQueryInfoKeyW( video_key, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &filetime ))
3836 return FALSE;
3837 if (CompareFileTime( &filetime, &last_query_display_time ) < 1)
3838 return TRUE;
3840 mutex = get_display_device_init_mutex();
3841 EnterCriticalSection( &display_section );
3843 LIST_FOR_EACH_ENTRY_SAFE(adapter, adapter2, &adapters, struct display_device, entry)
3845 LIST_FOR_EACH_ENTRY_SAFE(monitor, monitor2, &adapter->children, struct display_device, entry)
3847 list_remove( &monitor->entry );
3848 heap_free( monitor );
3850 list_remove( &adapter->entry );
3851 heap_free( adapter );
3854 for (adapter_idx = 0; enum_display_device( NULL, adapter_idx, &device ); ++adapter_idx)
3856 adapter = heap_alloc( sizeof(*adapter) );
3857 if (!adapter)
3858 goto fail;
3860 memcpy( adapter, &device, sizeof(device) );
3861 monitor_list = &adapter->children;
3862 list_init( monitor_list );
3863 list_add_tail( &adapters, &adapter->entry );
3864 for (monitor_idx = 0; enum_display_device( adapter->device_name, monitor_idx, &device ); ++monitor_idx)
3866 monitor = heap_alloc( sizeof(*monitor) );
3867 if (!monitor)
3868 goto fail;
3870 memcpy( monitor, &device, sizeof(device) );
3871 list_add_tail( monitor_list, &monitor->entry );
3875 last_query_display_time = filetime;
3876 ret = TRUE;
3877 fail:
3878 LeaveCriticalSection( &display_section );
3879 release_display_device_init_mutex( mutex );
3880 return ret;
3883 /* Return FALSE on failure and TRUE on success */
3884 static BOOL update_monitor_cache(void)
3886 SP_DEVINFO_DATA device_data = {sizeof(device_data)};
3887 HDEVINFO devinfo = INVALID_HANDLE_VALUE;
3888 MONITORINFOEXW *monitor_array;
3889 FILETIME filetime = {0};
3890 DWORD device_count = 0;
3891 HANDLE mutex = NULL;
3892 DWORD state_flags;
3893 BOOL ret = FALSE;
3894 BOOL is_replica;
3895 DWORD i = 0, j;
3896 DWORD type;
3898 /* Update monitor cache from SetupAPI if it's outdated */
3899 if (!video_key && RegOpenKeyW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", &video_key ))
3900 return FALSE;
3901 if (RegQueryInfoKeyW( video_key, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &filetime ))
3902 return FALSE;
3903 if (CompareFileTime( &filetime, &last_query_monitors_time ) < 1)
3904 return TRUE;
3906 mutex = get_display_device_init_mutex();
3907 EnterCriticalSection( &monitors_section );
3908 devinfo = SetupDiGetClassDevsW( &GUID_DEVCLASS_MONITOR, L"DISPLAY", NULL, DIGCF_PRESENT );
3910 while (SetupDiEnumDeviceInfo( devinfo, i++, &device_data ))
3912 /* Inactive monitors don't get enumerated */
3913 if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, &type,
3914 (BYTE *)&state_flags, sizeof(DWORD), NULL, 0 ))
3915 goto fail;
3916 if (state_flags & DISPLAY_DEVICE_ACTIVE)
3917 device_count++;
3920 if (device_count && monitor_count < device_count)
3922 monitor_array = heap_alloc( device_count * sizeof(*monitor_array) );
3923 if (!monitor_array)
3924 goto fail;
3925 heap_free( monitors );
3926 monitors = monitor_array;
3929 for (i = 0, monitor_count = 0; SetupDiEnumDeviceInfo( devinfo, i, &device_data ); i++)
3931 if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, &type,
3932 (BYTE *)&state_flags, sizeof(DWORD), NULL, 0 ))
3933 goto fail;
3934 if (!(state_flags & DISPLAY_DEVICE_ACTIVE))
3935 continue;
3936 if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCMONITOR, &type,
3937 (BYTE *)&monitors[monitor_count].rcMonitor, sizeof(RECT), NULL, 0 ))
3938 goto fail;
3940 /* Replicas in mirroring monitor sets don't get enumerated */
3941 is_replica = FALSE;
3942 for (j = 0; j < monitor_count; j++)
3944 if (EqualRect(&monitors[j].rcMonitor, &monitors[monitor_count].rcMonitor))
3946 is_replica = TRUE;
3947 break;
3950 if (is_replica)
3951 continue;
3953 if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCWORK, &type,
3954 (BYTE *)&monitors[monitor_count].rcWork, sizeof(RECT), NULL, 0 ))
3955 goto fail;
3956 if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_ADAPTERNAME, &type,
3957 (BYTE *)monitors[monitor_count].szDevice, CCHDEVICENAME * sizeof(WCHAR), NULL, 0))
3958 goto fail;
3959 monitors[monitor_count].dwFlags =
3960 !wcscmp( L"\\\\.\\DISPLAY1", monitors[monitor_count].szDevice ) ? MONITORINFOF_PRIMARY : 0;
3962 monitor_count++;
3965 last_query_monitors_time = filetime;
3966 ret = TRUE;
3967 fail:
3968 SetupDiDestroyDeviceInfoList( devinfo );
3969 LeaveCriticalSection( &monitors_section );
3970 release_display_device_init_mutex( mutex );
3971 return ret;
3974 BOOL CDECL nulldrv_GetMonitorInfo( HMONITOR handle, MONITORINFO *info )
3976 UINT index = (UINT_PTR)handle - 1;
3978 TRACE("(%p, %p)\n", handle, info);
3980 /* Fallback to report one monitor */
3981 if (handle == NULLDRV_DEFAULT_HMONITOR)
3983 RECT default_rect = {0, 0, 640, 480};
3984 info->rcMonitor = default_rect;
3985 info->rcWork = default_rect;
3986 info->dwFlags = MONITORINFOF_PRIMARY;
3987 if (info->cbSize >= sizeof(MONITORINFOEXW))
3988 lstrcpyW( ((MONITORINFOEXW *)info)->szDevice, L"\\\\.\\DISPLAY1" );
3989 return TRUE;
3992 if (!update_monitor_cache())
3993 return FALSE;
3995 EnterCriticalSection( &monitors_section );
3996 if (index < monitor_count)
3998 info->rcMonitor = monitors[index].rcMonitor;
3999 info->rcWork = monitors[index].rcWork;
4000 info->dwFlags = monitors[index].dwFlags;
4001 if (info->cbSize >= sizeof(MONITORINFOEXW))
4002 lstrcpyW( ((MONITORINFOEXW *)info)->szDevice, monitors[index].szDevice );
4003 LeaveCriticalSection( &monitors_section );
4004 return TRUE;
4006 else
4008 LeaveCriticalSection( &monitors_section );
4009 SetLastError( ERROR_INVALID_MONITOR_HANDLE );
4010 return FALSE;
4014 /***********************************************************************
4015 * GetMonitorInfoA (USER32.@)
4017 BOOL WINAPI GetMonitorInfoA( HMONITOR monitor, LPMONITORINFO info )
4019 MONITORINFOEXW miW;
4020 BOOL ret;
4022 if (info->cbSize == sizeof(MONITORINFO)) return GetMonitorInfoW( monitor, info );
4023 if (info->cbSize != sizeof(MONITORINFOEXA)) return FALSE;
4025 miW.cbSize = sizeof(miW);
4026 ret = GetMonitorInfoW( monitor, (MONITORINFO *)&miW );
4027 if (ret)
4029 MONITORINFOEXA *miA = (MONITORINFOEXA *)info;
4030 miA->rcMonitor = miW.rcMonitor;
4031 miA->rcWork = miW.rcWork;
4032 miA->dwFlags = miW.dwFlags;
4033 WideCharToMultiByte(CP_ACP, 0, miW.szDevice, -1, miA->szDevice, sizeof(miA->szDevice), NULL, NULL);
4035 return ret;
4038 /***********************************************************************
4039 * GetMonitorInfoW (USER32.@)
4041 BOOL WINAPI GetMonitorInfoW( HMONITOR monitor, LPMONITORINFO info )
4043 BOOL ret;
4044 UINT dpi_from, dpi_to;
4046 if (info->cbSize != sizeof(MONITORINFOEXW) && info->cbSize != sizeof(MONITORINFO)) return FALSE;
4048 ret = USER_Driver->pGetMonitorInfo( monitor, info );
4049 if (ret)
4051 if ((dpi_to = get_thread_dpi()))
4053 dpi_from = get_monitor_dpi( monitor );
4054 info->rcMonitor = map_dpi_rect( info->rcMonitor, dpi_from, dpi_to );
4055 info->rcWork = map_dpi_rect( info->rcWork, dpi_from, dpi_to );
4057 TRACE( "flags %04x, monitor %s, work %s\n", info->dwFlags,
4058 wine_dbgstr_rect(&info->rcMonitor), wine_dbgstr_rect(&info->rcWork));
4060 return ret;
4063 struct enum_mon_data
4065 MONITORENUMPROC proc;
4066 LPARAM lparam;
4067 HDC hdc;
4068 POINT origin;
4069 RECT limit;
4072 #ifdef __i386__
4073 /* Some apps pass a non-stdcall callback to EnumDisplayMonitors,
4074 * so we need a small assembly wrapper to call it.
4075 * MJ's Help Diagnostic expects that %ecx contains the address to the rect.
4077 extern BOOL enum_mon_callback_wrapper( HMONITOR monitor, LPRECT rect, struct enum_mon_data *data );
4078 __ASM_GLOBAL_FUNC( enum_mon_callback_wrapper,
4079 "pushl %ebp\n\t"
4080 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
4081 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
4082 "movl %esp,%ebp\n\t"
4083 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
4084 "subl $8,%esp\n\t"
4085 "movl 16(%ebp),%eax\n\t" /* data */
4086 "movl 12(%ebp),%ecx\n\t" /* rect */
4087 "pushl 4(%eax)\n\t" /* data->lparam */
4088 "pushl %ecx\n\t" /* rect */
4089 "pushl 8(%eax)\n\t" /* data->hdc */
4090 "pushl 8(%ebp)\n\t" /* monitor */
4091 "call *(%eax)\n\t" /* data->proc */
4092 "leave\n\t"
4093 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
4094 __ASM_CFI(".cfi_same_value %ebp\n\t")
4095 "ret" )
4096 #endif /* __i386__ */
4098 static BOOL CALLBACK enum_mon_callback( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
4100 struct enum_mon_data *data = (struct enum_mon_data *)lp;
4101 RECT monrect = map_dpi_rect( *rect, get_monitor_dpi( monitor ), get_thread_dpi() );
4103 OffsetRect( &monrect, -data->origin.x, -data->origin.y );
4104 if (!IntersectRect( &monrect, &monrect, &data->limit )) return TRUE;
4105 #ifdef __i386__
4106 return enum_mon_callback_wrapper( monitor, &monrect, data );
4107 #else
4108 return data->proc( monitor, data->hdc, &monrect, data->lparam );
4109 #endif
4112 BOOL CDECL nulldrv_EnumDisplayMonitors( HDC hdc, RECT *rect, MONITORENUMPROC proc, LPARAM lp )
4114 RECT monitor_rect;
4115 DWORD i = 0;
4117 TRACE("(%p, %p, %p, 0x%lx)\n", hdc, rect, proc, lp);
4119 if (update_monitor_cache())
4121 while (TRUE)
4123 EnterCriticalSection( &monitors_section );
4124 if (i >= monitor_count)
4126 LeaveCriticalSection( &monitors_section );
4127 return TRUE;
4129 monitor_rect = monitors[i].rcMonitor;
4130 LeaveCriticalSection( &monitors_section );
4132 if (!proc( (HMONITOR)(UINT_PTR)(i + 1), hdc, &monitor_rect, lp ))
4133 return FALSE;
4135 ++i;
4139 /* Fallback to report one monitor if using SetupAPI failed */
4140 SetRect( &monitor_rect, 0, 0, 640, 480 );
4141 if (!proc( NULLDRV_DEFAULT_HMONITOR, hdc, &monitor_rect, lp ))
4142 return FALSE;
4143 return TRUE;
4146 /***********************************************************************
4147 * EnumDisplayMonitors (USER32.@)
4149 BOOL WINAPI EnumDisplayMonitors( HDC hdc, LPRECT rect, MONITORENUMPROC proc, LPARAM lp )
4151 struct enum_mon_data data;
4153 data.proc = proc;
4154 data.lparam = lp;
4155 data.hdc = hdc;
4157 if (hdc)
4159 if (!GetDCOrgEx( hdc, &data.origin )) return FALSE;
4160 if (GetClipBox( hdc, &data.limit ) == ERROR) return FALSE;
4162 else
4164 data.origin.x = data.origin.y = 0;
4165 data.limit.left = data.limit.top = INT_MIN;
4166 data.limit.right = data.limit.bottom = INT_MAX;
4168 if (rect && !IntersectRect( &data.limit, &data.limit, rect )) return TRUE;
4169 return USER_Driver->pEnumDisplayMonitors( 0, NULL, enum_mon_callback, (LPARAM)&data );
4172 /***********************************************************************
4173 * EnumDisplayDevicesA (USER32.@)
4175 BOOL WINAPI EnumDisplayDevicesA( LPCSTR device, DWORD index, DISPLAY_DEVICEA *info, DWORD flags )
4177 UNICODE_STRING deviceW;
4178 DISPLAY_DEVICEW ddW;
4179 BOOL ret;
4181 if (device)
4182 RtlCreateUnicodeStringFromAsciiz( &deviceW, device );
4183 else
4184 deviceW.Buffer = NULL;
4186 ddW.cb = sizeof(ddW);
4187 ret = EnumDisplayDevicesW( deviceW.Buffer, index, &ddW, flags );
4188 RtlFreeUnicodeString( &deviceW );
4190 if (!ret)
4191 return ret;
4193 WideCharToMultiByte( CP_ACP, 0, ddW.DeviceName, -1, info->DeviceName, sizeof(info->DeviceName), NULL, NULL );
4194 WideCharToMultiByte( CP_ACP, 0, ddW.DeviceString, -1, info->DeviceString, sizeof(info->DeviceString), NULL, NULL );
4195 info->StateFlags = ddW.StateFlags;
4197 if (info->cb >= offsetof(DISPLAY_DEVICEA, DeviceID) + sizeof(info->DeviceID))
4198 WideCharToMultiByte( CP_ACP, 0, ddW.DeviceID, -1, info->DeviceID, sizeof(info->DeviceID), NULL, NULL );
4199 if (info->cb >= offsetof(DISPLAY_DEVICEA, DeviceKey) + sizeof(info->DeviceKey))
4200 WideCharToMultiByte( CP_ACP, 0, ddW.DeviceKey, -1, info->DeviceKey, sizeof(info->DeviceKey), NULL, NULL );
4202 return TRUE;
4205 /***********************************************************************
4206 * EnumDisplayDevicesW (USER32.@)
4208 BOOL WINAPI EnumDisplayDevicesW( LPCWSTR device, DWORD index, DISPLAY_DEVICEW *info, DWORD flags )
4210 struct display_device *adapter, *monitor, *found = NULL;
4211 DWORD device_idx = 0;
4213 TRACE("%s %u %p %#x\n", debugstr_w( device ), index, info, flags);
4215 if (!update_display_cache())
4216 return FALSE;
4218 EnterCriticalSection( &display_section );
4219 /* Enumerate adapters */
4220 if (!device)
4222 LIST_FOR_EACH_ENTRY(adapter, &adapters, struct display_device, entry)
4224 if (index == device_idx++)
4226 found = adapter;
4227 break;
4231 /* Enumerate monitors */
4232 else
4234 LIST_FOR_EACH_ENTRY(adapter, &adapters, struct display_device, entry)
4236 if (!lstrcmpiW( device, adapter->device_name ))
4238 found = adapter;
4239 break;
4243 if (found)
4245 found = NULL;
4246 LIST_FOR_EACH_ENTRY(monitor, &adapter->children, struct display_device, entry)
4248 if (index == device_idx++)
4250 found = monitor;
4251 break;
4257 if (!found)
4259 LeaveCriticalSection( &display_section );
4260 return FALSE;
4263 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceName) + sizeof(info->DeviceName))
4264 lstrcpyW( info->DeviceName, found->device_name );
4265 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceString) + sizeof(info->DeviceString))
4266 lstrcpyW( info->DeviceString, found->device_string );
4267 if (info->cb >= offsetof(DISPLAY_DEVICEW, StateFlags) + sizeof(info->StateFlags))
4268 info->StateFlags = found->state_flags;
4269 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->DeviceID))
4270 lstrcpyW( info->DeviceID, (flags & EDD_GET_DEVICE_INTERFACE_NAME) ? found->interface_name : found->device_id );
4271 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(info->DeviceKey))
4272 lstrcpyW( info->DeviceKey, found->device_key );
4273 LeaveCriticalSection( &display_section );
4274 return TRUE;
4277 /* Call this function with the display_device_init mutex held */
4278 static BOOL enum_display_device( WCHAR *device, DWORD index, struct display_device *info )
4280 SP_DEVINFO_DATA device_data = {sizeof(device_data)};
4281 HDEVINFO set = INVALID_HANDLE_VALUE;
4282 WCHAR key_nameW[MAX_PATH];
4283 WCHAR instanceW[MAX_PATH];
4284 WCHAR bufferW[1024];
4285 LONG adapter_index;
4286 WCHAR *next_charW;
4287 DWORD size;
4288 DWORD type;
4289 HKEY hkey;
4290 BOOL ret = FALSE;
4292 /* Find adapter */
4293 if (!device)
4295 swprintf( key_nameW, ARRAY_SIZE(key_nameW), L"\\Device\\Video%d", index );
4296 size = sizeof(bufferW);
4297 if (RegGetValueW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", key_nameW, RRF_RT_REG_SZ, NULL, bufferW, &size ))
4298 goto done;
4300 /* DeviceKey */
4301 lstrcpyW( info->device_key, bufferW );
4303 /* DeviceName */
4304 swprintf( info->device_name, ARRAY_SIZE(info->device_name), L"\\\\.\\DISPLAY%d", index + 1 );
4306 /* Strip \Registry\Machine\ */
4307 lstrcpyW( key_nameW, bufferW + 18 );
4309 /* DeviceString */
4310 size = sizeof(info->device_string);
4311 if (RegGetValueW( HKEY_LOCAL_MACHINE, key_nameW, L"DriverDesc", RRF_RT_REG_SZ, NULL,
4312 info->device_string, &size ))
4313 goto done;
4315 /* StateFlags */
4316 size = sizeof(info->state_flags);
4317 if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, L"StateFlags", RRF_RT_REG_DWORD, NULL,
4318 &info->state_flags, &size ))
4319 goto done;
4321 /* Interface name */
4322 info->interface_name[0] = 0;
4324 /* DeviceID */
4325 size = sizeof(bufferW);
4326 if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, L"GPUID", RRF_RT_REG_SZ | RRF_ZEROONFAILURE, NULL,
4327 bufferW, &size ))
4328 goto done;
4329 set = SetupDiCreateDeviceInfoList( &GUID_DEVCLASS_DISPLAY, NULL );
4330 if (!SetupDiOpenDeviceInfoW( set, bufferW, NULL, 0, &device_data )
4331 || !SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_HARDWAREID, NULL, (BYTE *)bufferW,
4332 sizeof(bufferW), NULL ))
4333 goto done;
4334 lstrcpyW( info->device_id, bufferW );
4336 /* Find monitor */
4337 else
4339 /* Check adapter name */
4340 if (wcsnicmp( device, L"\\\\.\\DISPLAY", lstrlenW(L"\\\\.\\DISPLAY") ))
4341 goto done;
4343 adapter_index = wcstol( device + lstrlenW(L"\\\\.\\DISPLAY"), NULL, 10 );
4344 swprintf( key_nameW, ARRAY_SIZE(key_nameW), L"\\Device\\Video%d", adapter_index - 1 );
4346 size = sizeof(bufferW);
4347 if (RegGetValueW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", key_nameW, RRF_RT_REG_SZ, NULL, bufferW, &size ))
4348 goto done;
4350 /* DeviceName */
4351 swprintf( info->device_name, ARRAY_SIZE(info->device_name), L"\\\\.\\DISPLAY%d\\Monitor%d", adapter_index, index );
4353 /* Get monitor instance */
4354 /* Strip \Registry\Machine\ first */
4355 lstrcpyW( key_nameW, bufferW + 18 );
4356 swprintf( bufferW, ARRAY_SIZE(bufferW), L"MonitorID%d", index );
4358 size = sizeof(instanceW);
4359 if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, bufferW, RRF_RT_REG_SZ, NULL, instanceW, &size ))
4360 goto done;
4362 set = SetupDiCreateDeviceInfoList( &GUID_DEVCLASS_MONITOR, NULL );
4363 if (!SetupDiOpenDeviceInfoW( set, instanceW, NULL, 0, &device_data ))
4364 goto done;
4366 /* StateFlags */
4367 if (!SetupDiGetDevicePropertyW( set, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, &type,
4368 (BYTE *)&info->state_flags, sizeof(info->state_flags), NULL, 0 ))
4369 goto done;
4371 /* DeviceString */
4372 if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_DEVICEDESC, NULL,
4373 (BYTE *)info->device_string,
4374 sizeof(info->device_string), NULL ))
4375 goto done;
4377 /* DeviceKey */
4378 if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW,
4379 sizeof(bufferW), NULL ))
4380 goto done;
4382 lstrcpyW( info->device_key, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\" );
4383 lstrcatW( info->device_key, bufferW );
4385 /* Interface name */
4386 lstrcpyW( info->interface_name, L"\\\\\?\\" );
4387 lstrcatW( info->interface_name, instanceW );
4388 lstrcatW( info->interface_name, L"#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}" );
4389 /* Replace '\\' with '#' after prefix */
4390 for (next_charW = info->interface_name + lstrlenW( L"\\\\\?\\" ); *next_charW; next_charW++)
4392 if (*next_charW == '\\')
4393 *next_charW = '#';
4396 /* DeviceID */
4397 if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_HARDWAREID, NULL, (BYTE *)bufferW,
4398 sizeof(bufferW), NULL ))
4399 goto done;
4401 lstrcpyW( info->device_id, bufferW );
4402 lstrcatW( info->device_id, L"\\" );
4404 if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW,
4405 sizeof(bufferW), NULL ))
4406 goto done;
4408 lstrcatW( info->device_id, bufferW );
4411 ret = TRUE;
4412 done:
4413 SetupDiDestroyDeviceInfoList( set );
4414 if (ret)
4415 return ret;
4417 /* Fallback to report at least one adapter and monitor, if user driver didn't initialize display device registry */
4418 if (index)
4419 return FALSE;
4421 /* If user driver did initialize the registry, then exit */
4422 if (!RegOpenKeyW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", &hkey ))
4424 RegCloseKey( hkey );
4425 return FALSE;
4427 WARN("Reporting fallback display devices\n");
4429 /* Adapter */
4430 if (!device)
4432 lstrcpyW( info->device_name, L"\\\\.\\DISPLAY1" );
4433 lstrcpyW( info->device_string, L"Wine Adapter" );
4434 info->state_flags = DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_PRIMARY_DEVICE | DISPLAY_DEVICE_VGA_COMPATIBLE;
4435 info->interface_name[0] = 0;
4436 lstrcpyW( info->device_id, L"PCI\\VEN_0000&DEV_0000&SUBSYS_00000000&REV_00" );
4437 info->device_key[0] = 0;
4439 /* Monitor */
4440 else
4442 if (lstrcmpiW( L"\\\\.\\DISPLAY1", device ))
4443 return FALSE;
4445 lstrcpyW( info->device_name, L"\\\\.\\DISPLAY1\\Monitor0" );
4446 lstrcpyW( info->device_string, L"Generic Non-PnP Monitor" );
4447 info->state_flags = DISPLAY_DEVICE_ACTIVE | DISPLAY_DEVICE_ATTACHED;
4448 lstrcpyW( info->interface_name, L"\\\\\?\\DISPLAY#Default_Monitor#4&17f0ff54&0&UID0#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}" );
4449 lstrcpyW( info->device_id, L"MONITOR\\Default_Monitor\\{4d36e96e-e325-11ce-bfc1-08002be10318}\\0000" );
4450 info->device_key[0] = 0;
4453 return TRUE;
4456 /**********************************************************************
4457 * GetAutoRotationState [USER32.@]
4459 BOOL WINAPI GetAutoRotationState( AR_STATE *state )
4461 TRACE("(%p)\n", state);
4463 if (!state)
4465 SetLastError(ERROR_INVALID_PARAMETER);
4466 return FALSE;
4469 *state = AR_NOSENSOR;
4470 return TRUE;
4473 /**********************************************************************
4474 * GetDisplayAutoRotationPreferences [USER32.@]
4476 BOOL WINAPI GetDisplayAutoRotationPreferences( ORIENTATION_PREFERENCE *orientation )
4478 FIXME("(%p): stub\n", orientation);
4479 *orientation = ORIENTATION_PREFERENCE_NONE;
4480 return TRUE;
4483 /* physical<->logical mapping functions from win8 that are nops in later versions */
4485 /***********************************************************************
4486 * GetPhysicalCursorPos (USER32.@)
4488 BOOL WINAPI GetPhysicalCursorPos( POINT *point )
4490 return GetCursorPos( point );
4493 /***********************************************************************
4494 * SetPhysicalCursorPos (USER32.@)
4496 BOOL WINAPI SetPhysicalCursorPos( INT x, INT y )
4498 return SetCursorPos( x, y );
4501 /***********************************************************************
4502 * LogicalToPhysicalPoint (USER32.@)
4504 BOOL WINAPI LogicalToPhysicalPoint( HWND hwnd, POINT *point )
4506 return TRUE;
4509 /***********************************************************************
4510 * PhysicalToLogicalPoint (USER32.@)
4512 BOOL WINAPI PhysicalToLogicalPoint( HWND hwnd, POINT *point )
4514 return TRUE;
4517 /**********************************************************************
4518 * GetDisplayConfigBufferSizes (USER32.@)
4520 LONG WINAPI GetDisplayConfigBufferSizes(UINT32 flags, UINT32 *num_path_info, UINT32 *num_mode_info)
4522 LONG ret = ERROR_GEN_FAILURE;
4523 HANDLE mutex;
4524 HDEVINFO devinfo;
4525 SP_DEVINFO_DATA device_data = {sizeof(device_data)};
4526 DWORD monitor_index = 0, state_flags, type;
4528 FIXME("(0x%x %p %p): semi-stub\n", flags, num_path_info, num_mode_info);
4530 if (!num_path_info || !num_mode_info)
4531 return ERROR_INVALID_PARAMETER;
4533 *num_path_info = 0;
4535 if (flags != QDC_ALL_PATHS &&
4536 flags != QDC_ONLY_ACTIVE_PATHS &&
4537 flags != QDC_DATABASE_CURRENT)
4538 return ERROR_INVALID_PARAMETER;
4540 if (flags != QDC_ONLY_ACTIVE_PATHS)
4541 FIXME("only returning active paths\n");
4543 wait_graphics_driver_ready();
4544 mutex = get_display_device_init_mutex();
4546 /* Iterate through "targets"/monitors.
4547 * Each target corresponds to a path, and each path references a source and a target mode.
4549 devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, L"DISPLAY", NULL, DIGCF_PRESENT);
4550 if (devinfo == INVALID_HANDLE_VALUE)
4551 goto done;
4553 while (SetupDiEnumDeviceInfo(devinfo, monitor_index++, &device_data))
4555 /* Only count active monitors */
4556 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS,
4557 &type, (BYTE *)&state_flags, sizeof(state_flags), NULL, 0))
4558 goto done;
4560 if (state_flags & DISPLAY_DEVICE_ACTIVE)
4561 (*num_path_info)++;
4564 *num_mode_info = *num_path_info * 2;
4565 ret = ERROR_SUCCESS;
4566 TRACE("returning %u path(s) %u mode(s)\n", *num_path_info, *num_mode_info);
4568 done:
4569 SetupDiDestroyDeviceInfoList(devinfo);
4570 release_display_device_init_mutex(mutex);
4571 return ret;
4574 static DISPLAYCONFIG_ROTATION get_dc_rotation(const DEVMODEW *devmode)
4576 if (devmode->dmFields & DM_DISPLAYORIENTATION)
4577 return devmode->u1.s2.dmDisplayOrientation + 1;
4578 else
4579 return DISPLAYCONFIG_ROTATION_IDENTITY;
4582 static DISPLAYCONFIG_SCANLINE_ORDERING get_dc_scanline_ordering(const DEVMODEW *devmode)
4584 if (!(devmode->dmFields & DM_DISPLAYFLAGS))
4585 return DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED;
4586 else if (devmode->u2.dmDisplayFlags & DM_INTERLACED)
4587 return DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED;
4588 else
4589 return DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE;
4592 static DISPLAYCONFIG_PIXELFORMAT get_dc_pixelformat(DWORD dmBitsPerPel)
4594 if ((dmBitsPerPel == 8) || (dmBitsPerPel == 16) ||
4595 (dmBitsPerPel == 24) || (dmBitsPerPel == 32))
4596 return dmBitsPerPel / 8;
4597 else
4598 return DISPLAYCONFIG_PIXELFORMAT_NONGDI;
4601 static void set_mode_target_info(DISPLAYCONFIG_MODE_INFO *info, const LUID *gpu_luid, UINT32 target_id,
4602 UINT32 flags, const DEVMODEW *devmode)
4604 DISPLAYCONFIG_TARGET_MODE *mode = &(info->u.targetMode);
4606 info->infoType = DISPLAYCONFIG_MODE_INFO_TYPE_TARGET;
4607 info->adapterId = *gpu_luid;
4608 info->id = target_id;
4610 /* FIXME: Populate pixelRate/hSyncFreq/totalSize with real data */
4611 mode->targetVideoSignalInfo.pixelRate = devmode->dmDisplayFrequency * devmode->dmPelsWidth * devmode->dmPelsHeight;
4612 mode->targetVideoSignalInfo.hSyncFreq.Numerator = devmode->dmDisplayFrequency * devmode->dmPelsWidth;
4613 mode->targetVideoSignalInfo.hSyncFreq.Denominator = 1;
4614 mode->targetVideoSignalInfo.vSyncFreq.Numerator = devmode->dmDisplayFrequency;
4615 mode->targetVideoSignalInfo.vSyncFreq.Denominator = 1;
4616 mode->targetVideoSignalInfo.activeSize.cx = devmode->dmPelsWidth;
4617 mode->targetVideoSignalInfo.activeSize.cy = devmode->dmPelsHeight;
4618 if (flags & QDC_DATABASE_CURRENT)
4620 mode->targetVideoSignalInfo.totalSize.cx = 0;
4621 mode->targetVideoSignalInfo.totalSize.cy = 0;
4623 else
4625 mode->targetVideoSignalInfo.totalSize.cx = devmode->dmPelsWidth;
4626 mode->targetVideoSignalInfo.totalSize.cy = devmode->dmPelsHeight;
4628 mode->targetVideoSignalInfo.u.videoStandard = D3DKMDT_VSS_OTHER;
4629 mode->targetVideoSignalInfo.scanLineOrdering = get_dc_scanline_ordering(devmode);
4632 static void set_path_target_info(DISPLAYCONFIG_PATH_TARGET_INFO *info, const LUID *gpu_luid,
4633 UINT32 target_id, UINT32 mode_index, const DEVMODEW *devmode)
4635 info->adapterId = *gpu_luid;
4636 info->id = target_id;
4637 info->u.modeInfoIdx = mode_index;
4638 info->outputTechnology = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL;
4639 info->rotation = get_dc_rotation(devmode);
4640 info->scaling = DISPLAYCONFIG_SCALING_IDENTITY;
4641 info->refreshRate.Numerator = devmode->dmDisplayFrequency;
4642 info->refreshRate.Denominator = 1;
4643 info->scanLineOrdering = get_dc_scanline_ordering(devmode);
4644 info->targetAvailable = TRUE;
4645 info->statusFlags = DISPLAYCONFIG_TARGET_IN_USE;
4648 static void set_mode_source_info(DISPLAYCONFIG_MODE_INFO *info, const LUID *gpu_luid,
4649 UINT32 source_id, const DEVMODEW *devmode)
4651 DISPLAYCONFIG_SOURCE_MODE *mode = &(info->u.sourceMode);
4653 info->infoType = DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE;
4654 info->adapterId = *gpu_luid;
4655 info->id = source_id;
4657 mode->width = devmode->dmPelsWidth;
4658 mode->height = devmode->dmPelsHeight;
4659 mode->pixelFormat = get_dc_pixelformat(devmode->dmBitsPerPel);
4660 if (devmode->dmFields & DM_POSITION)
4662 mode->position = devmode->u1.s2.dmPosition;
4664 else
4666 mode->position.x = 0;
4667 mode->position.y = 0;
4671 static void set_path_source_info(DISPLAYCONFIG_PATH_SOURCE_INFO *info, const LUID *gpu_luid,
4672 UINT32 source_id, UINT32 mode_index)
4674 info->adapterId = *gpu_luid;
4675 info->id = source_id;
4676 info->u.modeInfoIdx = mode_index;
4677 info->statusFlags = DISPLAYCONFIG_SOURCE_IN_USE;
4680 static BOOL source_mode_exists(const DISPLAYCONFIG_MODE_INFO *modeinfo, UINT32 num_modes,
4681 UINT32 source_id, UINT32 *found_mode_index)
4683 UINT32 i;
4685 for (i = 0; i < num_modes; i++)
4687 if (modeinfo[i].infoType == DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE &&
4688 modeinfo[i].id == source_id)
4690 *found_mode_index = i;
4691 return TRUE;
4694 return FALSE;
4697 /***********************************************************************
4698 * QueryDisplayConfig (USER32.@)
4700 LONG WINAPI QueryDisplayConfig(UINT32 flags, UINT32 *numpathelements, DISPLAYCONFIG_PATH_INFO *pathinfo,
4701 UINT32 *numinfoelements, DISPLAYCONFIG_MODE_INFO *modeinfo,
4702 DISPLAYCONFIG_TOPOLOGY_ID *topologyid)
4704 LONG adapter_index, ret;
4705 HANDLE mutex;
4706 HDEVINFO devinfo;
4707 SP_DEVINFO_DATA device_data = {sizeof(device_data)};
4708 DWORD monitor_index = 0, state_flags, type;
4709 UINT32 output_id, source_mode_index, path_index = 0, mode_index = 0;
4710 LUID gpu_luid;
4711 WCHAR device_name[CCHDEVICENAME];
4712 DEVMODEW devmode;
4714 FIXME("(%08x %p %p %p %p %p): semi-stub\n", flags, numpathelements, pathinfo, numinfoelements, modeinfo, topologyid);
4716 if (!numpathelements || !numinfoelements)
4717 return ERROR_INVALID_PARAMETER;
4719 if (!*numpathelements || !*numinfoelements)
4720 return ERROR_INVALID_PARAMETER;
4722 if (flags != QDC_ALL_PATHS &&
4723 flags != QDC_ONLY_ACTIVE_PATHS &&
4724 flags != QDC_DATABASE_CURRENT)
4725 return ERROR_INVALID_PARAMETER;
4727 if (((flags == QDC_DATABASE_CURRENT) && !topologyid) ||
4728 ((flags != QDC_DATABASE_CURRENT) && topologyid))
4729 return ERROR_INVALID_PARAMETER;
4731 if (flags != QDC_ONLY_ACTIVE_PATHS)
4732 FIXME("only returning active paths\n");
4734 if (topologyid)
4736 FIXME("setting toplogyid to DISPLAYCONFIG_TOPOLOGY_INTERNAL\n");
4737 *topologyid = DISPLAYCONFIG_TOPOLOGY_INTERNAL;
4740 wait_graphics_driver_ready();
4741 mutex = get_display_device_init_mutex();
4743 /* Iterate through "targets"/monitors.
4744 * Each target corresponds to a path, and each path corresponds to one or two unique modes.
4746 devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, L"DISPLAY", NULL, DIGCF_PRESENT);
4747 if (devinfo == INVALID_HANDLE_VALUE)
4749 ret = ERROR_GEN_FAILURE;
4750 goto done;
4753 ret = ERROR_GEN_FAILURE;
4754 while (SetupDiEnumDeviceInfo(devinfo, monitor_index++, &device_data))
4756 /* Only count active monitors */
4757 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS,
4758 &type, (BYTE *)&state_flags, sizeof(state_flags), NULL, 0))
4759 goto done;
4760 if (!(state_flags & DISPLAY_DEVICE_ACTIVE))
4761 continue;
4763 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPROPKEY_MONITOR_GPU_LUID,
4764 &type, (BYTE *)&gpu_luid, sizeof(gpu_luid), NULL, 0))
4765 goto done;
4767 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPROPKEY_MONITOR_OUTPUT_ID,
4768 &type, (BYTE *)&output_id, sizeof(output_id), NULL, 0))
4769 goto done;
4771 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_ADAPTERNAME,
4772 &type, (BYTE *)device_name, sizeof(device_name), NULL, 0))
4773 goto done;
4775 memset(&devmode, 0, sizeof(devmode));
4776 devmode.dmSize = sizeof(devmode);
4777 if (!EnumDisplaySettingsW(device_name, ENUM_CURRENT_SETTINGS, &devmode))
4778 goto done;
4780 /* Extract the adapter index from device_name to use as the source ID */
4781 adapter_index = wcstol(device_name + lstrlenW(L"\\\\.\\DISPLAY"), NULL, 10);
4782 adapter_index--;
4784 if (path_index == *numpathelements || mode_index == *numinfoelements)
4786 ret = ERROR_INSUFFICIENT_BUFFER;
4787 goto done;
4790 pathinfo[path_index].flags = DISPLAYCONFIG_PATH_ACTIVE;
4791 set_mode_target_info(&modeinfo[mode_index], &gpu_luid, output_id, flags, &devmode);
4792 set_path_target_info(&(pathinfo[path_index].targetInfo), &gpu_luid, output_id, mode_index, &devmode);
4794 mode_index++;
4795 if (mode_index == *numinfoelements)
4797 ret = ERROR_INSUFFICIENT_BUFFER;
4798 goto done;
4801 /* Multiple targets can be driven by the same source, ensure a mode
4802 * hasn't already been added for this source.
4804 if (!source_mode_exists(modeinfo, mode_index, adapter_index, &source_mode_index))
4806 set_mode_source_info(&modeinfo[mode_index], &gpu_luid, adapter_index, &devmode);
4807 source_mode_index = mode_index;
4808 mode_index++;
4810 set_path_source_info(&(pathinfo[path_index].sourceInfo), &gpu_luid, adapter_index, source_mode_index);
4811 path_index++;
4814 *numpathelements = path_index;
4815 *numinfoelements = mode_index;
4816 ret = ERROR_SUCCESS;
4818 done:
4819 SetupDiDestroyDeviceInfoList(devinfo);
4820 release_display_device_init_mutex(mutex);
4821 return ret;
4824 /***********************************************************************
4825 * DisplayConfigGetDeviceInfo (USER32.@)
4827 LONG WINAPI DisplayConfigGetDeviceInfo(DISPLAYCONFIG_DEVICE_INFO_HEADER *packet)
4829 LONG ret = ERROR_GEN_FAILURE;
4830 HANDLE mutex;
4831 HDEVINFO devinfo;
4832 SP_DEVINFO_DATA device_data = {sizeof(device_data)};
4833 DWORD index = 0, type;
4834 LUID gpu_luid;
4836 TRACE("(%p)\n", packet);
4838 if (!packet || packet->size < sizeof(*packet))
4839 return ERROR_GEN_FAILURE;
4840 wait_graphics_driver_ready();
4842 switch (packet->type)
4844 case DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME:
4846 DISPLAYCONFIG_SOURCE_DEVICE_NAME *source_name = (DISPLAYCONFIG_SOURCE_DEVICE_NAME *)packet;
4847 WCHAR device_name[CCHDEVICENAME];
4848 LONG source_id;
4850 TRACE("DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME\n");
4852 if (packet->size < sizeof(*source_name))
4853 return ERROR_INVALID_PARAMETER;
4855 mutex = get_display_device_init_mutex();
4856 devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, L"DISPLAY", NULL, DIGCF_PRESENT);
4857 if (devinfo == INVALID_HANDLE_VALUE)
4859 release_display_device_init_mutex(mutex);
4860 return ret;
4863 while (SetupDiEnumDeviceInfo(devinfo, index++, &device_data))
4865 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPROPKEY_MONITOR_GPU_LUID,
4866 &type, (BYTE *)&gpu_luid, sizeof(gpu_luid), NULL, 0))
4867 continue;
4869 if ((source_name->header.adapterId.LowPart != gpu_luid.LowPart) ||
4870 (source_name->header.adapterId.HighPart != gpu_luid.HighPart))
4871 continue;
4873 /* QueryDisplayConfig() derives the source ID from the adapter name. */
4874 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_ADAPTERNAME,
4875 &type, (BYTE *)device_name, sizeof(device_name), NULL, 0))
4876 continue;
4878 source_id = wcstol(device_name + lstrlenW(L"\\\\.\\DISPLAY"), NULL, 10);
4879 source_id--;
4880 if (source_name->header.id != source_id)
4881 continue;
4883 lstrcpyW(source_name->viewGdiDeviceName, device_name);
4884 ret = ERROR_SUCCESS;
4885 break;
4887 SetupDiDestroyDeviceInfoList(devinfo);
4888 release_display_device_init_mutex(mutex);
4889 return ret;
4891 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME:
4893 DISPLAYCONFIG_TARGET_DEVICE_NAME *target_name = (DISPLAYCONFIG_TARGET_DEVICE_NAME *)packet;
4895 FIXME("DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME: stub\n");
4897 if (packet->size < sizeof(*target_name))
4898 return ERROR_INVALID_PARAMETER;
4900 return ERROR_NOT_SUPPORTED;
4902 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE:
4904 DISPLAYCONFIG_TARGET_PREFERRED_MODE *preferred_mode = (DISPLAYCONFIG_TARGET_PREFERRED_MODE *)packet;
4906 FIXME("DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE: stub\n");
4908 if (packet->size < sizeof(*preferred_mode))
4909 return ERROR_INVALID_PARAMETER;
4911 return ERROR_NOT_SUPPORTED;
4913 case DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME:
4915 DISPLAYCONFIG_ADAPTER_NAME *adapter_name = (DISPLAYCONFIG_ADAPTER_NAME *)packet;
4917 FIXME("DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME: stub\n");
4919 if (packet->size < sizeof(*adapter_name))
4920 return ERROR_INVALID_PARAMETER;
4922 return ERROR_NOT_SUPPORTED;
4924 case DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE:
4925 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE:
4926 case DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION:
4927 case DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION:
4928 case DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO:
4929 case DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE:
4930 case DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL:
4931 default:
4932 FIXME("Unimplemented packet type: %u\n", packet->type);
4933 return ERROR_INVALID_PARAMETER;
4937 /***********************************************************************
4938 * SetDisplayConfig (USER32.@)
4940 LONG WINAPI SetDisplayConfig(UINT32 path_info_count, DISPLAYCONFIG_PATH_INFO *path_info, UINT32 mode_info_count,
4941 DISPLAYCONFIG_MODE_INFO *mode_info, UINT32 flags)
4943 FIXME("path_info_count %u, path_info %p, mode_info_count %u, mode_info %p, flags %#x stub.\n",
4944 path_info_count, path_info, mode_info_count, mode_info, flags);
4946 return ERROR_SUCCESS;