mfmediaengine: Remove unnecessary import library.
[wine.git] / dlls / win32u / sysparams.c
blob4c65bd9d7f14274486c4bad10d9aff1a5c35c842
1 /*
2 * System parameters functions
4 * Copyright 1994 Alexandre Julliard
5 * Copyright 2019 Zhiyi Zhang for CodeWeavers
6 * Copyright 2021 Jacek Caban for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #if 0
24 #pragma makedep unix
25 #endif
27 #include <pthread.h>
28 #include "ntstatus.h"
29 #define WIN32_NO_STATUS
30 #include "ntgdi_private.h"
31 #include "devpropdef.h"
32 #include "wine/wingdi16.h"
33 #include "wine/server.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(system);
38 static HKEY video_key, enum_key, control_key, config_key, volatile_base_key;
40 static const WCHAR devicemap_video_keyW[] =
42 '\\','R','e','g','i','s','t','r','y',
43 '\\','M','a','c','h','i','n','e',
44 '\\','H','A','R','D','W','A','R','E',
45 '\\','D','E','V','I','C','E','M','A','P',
46 '\\','V','I','D','E','O'
49 static const WCHAR enum_keyW[] =
51 '\\','R','e','g','i','s','t','r','y',
52 '\\','M','a','c','h','i','n','e',
53 '\\','S','y','s','t','e','m',
54 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
55 '\\','E','n','u','m'
58 static const WCHAR control_keyW[] =
60 '\\','R','e','g','i','s','t','r','y',
61 '\\','M','a','c','h','i','n','e',
62 '\\','S','y','s','t','e','m',
63 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
64 '\\','C','o','n','t','r','o','l'
67 static const WCHAR config_keyW[] =
69 '\\','R','e','g','i','s','t','r','y',
70 '\\','M','a','c','h','i','n','e',
71 '\\','S','y','s','t','e','m',
72 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
73 '\\','H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s',
74 '\\','C','u','r','r','e','n','t'
77 static const WCHAR devpropkey_gpu_vulkan_uuidW[] =
79 'P','r','o','p','e','r','t','i','e','s',
80 '\\','{','2','3','3','A','9','E','F','3','-','A','F','C','4','-','4','A','B','D',
81 '-','B','5','6','4','-','C','3','2','F','2','1','F','1','5','3','5','C','}',
82 '\\','0','0','0','2'
85 static const WCHAR devpropkey_gpu_luidW[] =
87 'P','r','o','p','e','r','t','i','e','s',
88 '\\','{','6','0','B','1','9','3','C','B','-','5','2','7','6','-','4','D','0','F',
89 '-','9','6','F','C','-','F','1','7','3','A','B','A','D','3','E','C','6','}',
90 '\\','0','0','0','2'
93 static const WCHAR devpropkey_device_ispresentW[] =
95 'P','r','o','p','e','r','t','i','e','s',
96 '\\','{','5','4','0','B','9','4','7','E','-','8','B','4','0','-','4','5','B','C',
97 '-','A','8','A','2','-','6','A','0','B','8','9','4','C','B','D','A','2','}',
98 '\\','0','0','0','5'
101 static const WCHAR devpropkey_monitor_gpu_luidW[] =
103 'P','r','o','p','e','r','t','i','e','s',
104 '\\','{','C','A','0','8','5','8','5','3','-','1','6','C','E','-','4','8','A','A',
105 '-','B','1','1','4','-','D','E','9','C','7','2','3','3','4','2','2','3','}',
106 '\\','0','0','0','1'
109 static const WCHAR devpropkey_monitor_output_idW[] =
111 'P','r','o','p','e','r','t','i','e','s',
112 '\\','{','C','A','0','8','5','8','5','3','-','1','6','C','E','-','4','8','A','A',
113 '-','B','1','1','4','-','D','E','9','C','7','2','3','3','4','2','2','3','}',
114 '\\','0','0','0','2'
117 static const WCHAR wine_devpropkey_monitor_stateflagsW[] =
119 'P','r','o','p','e','r','t','i','e','s','\\',
120 '{','2','3','3','a','9','e','f','3','-','a','f','c','4','-','4','a','b','d',
121 '-','b','5','6','4','-','c','3','2','f','2','1','f','1','5','3','5','b','}',
122 '\\','0','0','0','2'
125 static const WCHAR wine_devpropkey_monitor_rcmonitorW[] =
127 'P','r','o','p','e','r','t','i','e','s','\\',
128 '{','2','3','3','a','9','e','f','3','-','a','f','c','4','-','4','a','b','d',
129 '-','b','5','6','4','-','c','3','2','f','2','1','f','1','5','3','5','b','}',
130 '\\','0','0','0','3'
133 static const WCHAR wine_devpropkey_monitor_rcworkW[] =
135 'P','r','o','p','e','r','t','i','e','s','\\',
136 '{','2','3','3','a','9','e','f','3','-','a','f','c','4','-','4','a','b','d',
137 '-','b','5','6','4','-','c','3','2','f','2','1','f','1','5','3','5','b','}',
138 '\\','0','0','0','4'
141 static const WCHAR wine_devpropkey_monitor_adapternameW[] =
143 'P','r','o','p','e','r','t','i','e','s','\\',
144 '{','2','3','3','a','9','e','f','3','-','a','f','c','4','-','4','a','b','d',
145 '-','b','5','6','4','-','c','3','2','f','2','1','f','1','5','3','5','b','}',
146 '\\','0','0','0','5'
149 static const WCHAR device_instanceW[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
150 static const WCHAR controlW[] = {'C','o','n','t','r','o','l'};
151 static const WCHAR device_parametersW[] =
152 {'D','e','v','i','c','e',' ','P','a','r','a','m','e','t','e','r','s'};
153 static const WCHAR linkedW[] = {'L','i','n','k','e','d',0};
154 static const WCHAR symbolic_link_valueW[] =
155 {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
156 static const WCHAR state_flagsW[] = {'S','t','a','t','e','F','l','a','g','s',0};
157 static const WCHAR gpu_idW[] = {'G','P','U','I','D',0};
158 static const WCHAR hardware_idW[] = {'H','a','r','d','w','a','r','e','I','D',0};
159 static const WCHAR device_descW[] = {'D','e','v','i','c','e','D','e','s','c',0};
160 static const WCHAR driver_descW[] = {'D','r','i','v','e','r','D','e','s','c',0};
161 static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
162 static const WCHAR class_guidW[] = {'C','l','a','s','s','G','U','I','D',0};
163 static const WCHAR pciW[] = {'P','C','I'};
164 static const WCHAR classW[] = {'C','l','a','s','s',0};
165 static const WCHAR displayW[] = {'D','i','s','p','l','a','y',0};
166 static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0};
167 static const WCHAR yesW[] = {'Y','e','s',0};
168 static const WCHAR noW[] = {'N','o',0};
170 static const char guid_devclass_displayA[] = "{4D36E968-E325-11CE-BFC1-08002BE10318}";
171 static const WCHAR guid_devclass_displayW[] =
172 {'{','4','D','3','6','E','9','6','8','-','E','3','2','5','-','1','1','C','E','-',
173 'B','F','C','1','-','0','8','0','0','2','B','E','1','0','3','1','8','}',0};
175 static const char guid_devclass_monitorA[] = "{4D36E96E-E325-11CE-BFC1-08002BE10318}";
176 static const WCHAR guid_devclass_monitorW[] =
177 {'{','4','D','3','6','E','9','6','E','-','E','3','2','5','-','1','1','C','E','-'
178 ,'B','F','C','1','-','0','8','0','0','2','B','E','1','0','3','1','8','}'};
180 static const WCHAR guid_devinterface_display_adapterW[] =
181 {'{','5','B','4','5','2','0','1','D','-','F','2','F','2','-','4','F','3','B','-',
182 '8','5','B','B','-','3','0','F','F','1','F','9','5','3','5','9','9','}',0};
184 static const WCHAR guid_display_device_arrivalW[] =
185 {'{','1','C','A','0','5','1','8','0','-','A','6','9','9','-','4','5','0','A','-',
186 '9','A','0','C','-','D','E','4','F','B','E','3','D','D','D','8','9','}',0};
188 static const WCHAR guid_devinterface_monitorW[] =
189 {'{','E','6','F','0','7','B','5','F','-','E','E','9','7','-','4','A','9','0','-',
190 'B','0','7','6','-','3','3','F','5','7','B','F','4','E','A','A','7','}',0};
192 #define NULLDRV_DEFAULT_HMONITOR ((HMONITOR)(UINT_PTR)(0x10000 + 1))
194 /* Cached display device information */
195 struct display_device
197 WCHAR device_name[32]; /* DeviceName in DISPLAY_DEVICEW */
198 WCHAR device_string[128]; /* DeviceString in DISPLAY_DEVICEW */
199 DWORD state_flags; /* StateFlags in DISPLAY_DEVICEW */
200 WCHAR device_id[128]; /* DeviceID in DISPLAY_DEVICEW */
201 WCHAR interface_name[128]; /* DeviceID in DISPLAY_DEVICEW when EDD_GET_DEVICE_INTERFACE_NAME is set */
202 WCHAR device_key[128]; /* DeviceKey in DISPLAY_DEVICEW */
205 struct adapter
207 struct list entry;
208 struct display_device dev;
209 unsigned int id;
210 const WCHAR *config_key;
213 struct monitor
215 struct list entry;
216 struct display_device dev;
217 struct adapter *adapter;
218 HANDLE handle;
219 unsigned int id;
220 unsigned int flags;
221 RECT rc_monitor;
222 RECT rc_work;
225 static struct list adapters = LIST_INIT(adapters);
226 static struct list monitors = LIST_INIT(monitors);
227 static INT64 last_query_display_time;
228 static pthread_mutex_t display_lock = PTHREAD_MUTEX_INITIALIZER;
230 static struct monitor virtual_monitor =
232 .handle = NULLDRV_DEFAULT_HMONITOR,
233 .flags = MONITORINFOF_PRIMARY,
234 .rc_monitor.right = 1024,
235 .rc_monitor.bottom = 768,
236 .rc_work.right = 1024,
237 .rc_work.bottom = 768,
238 .dev.state_flags = DISPLAY_DEVICE_ACTIVE | DISPLAY_DEVICE_ATTACHED,
241 /* the various registry keys that are used to store parameters */
242 enum parameter_key
244 COLORS_KEY,
245 DESKTOP_KEY,
246 KEYBOARD_KEY,
247 MOUSE_KEY,
248 METRICS_KEY,
249 SOUND_KEY,
250 VERSION_KEY,
251 SHOWSOUNDS_KEY,
252 KEYBOARDPREF_KEY,
253 SCREENREADER_KEY,
254 AUDIODESC_KEY,
255 NB_PARAM_KEYS
258 static const char *parameter_key_names[NB_PARAM_KEYS] =
260 "Control Panel\\Colors",
261 "Control Panel\\Desktop",
262 "Control Panel\\Keyboard",
263 "Control Panel\\Mouse",
264 "Control Panel\\Desktop\\WindowMetrics",
265 "Control Panel\\Sound",
266 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows",
267 "Control Panel\\Accessibility\\ShowSounds",
268 "Control Panel\\Accessibility\\Keyboard Preference",
269 "Control Panel\\Accessibility\\Blind Access",
270 "Control Panel\\Accessibility\\AudioDescription",
273 /* System parameters storage */
274 union sysparam_all_entry;
276 struct sysparam_entry
278 BOOL (*get)( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi );
279 BOOL (*set)( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags );
280 BOOL (*init)( union sysparam_all_entry *entry );
281 enum parameter_key base_key;
282 const char *regval;
283 enum parameter_key mirror_key;
284 const char *mirror;
285 BOOL loaded;
288 struct sysparam_uint_entry
290 struct sysparam_entry hdr;
291 UINT val;
294 struct sysparam_bool_entry
296 struct sysparam_entry hdr;
297 BOOL val;
300 struct sysparam_dword_entry
302 struct sysparam_entry hdr;
303 DWORD val;
306 struct sysparam_rgb_entry
308 struct sysparam_entry hdr;
309 COLORREF val;
310 HBRUSH brush;
311 HPEN pen;
314 struct sysparam_binary_entry
316 struct sysparam_entry hdr;
317 void *ptr;
318 size_t size;
321 struct sysparam_path_entry
323 struct sysparam_entry hdr;
324 WCHAR path[MAX_PATH];
327 struct sysparam_font_entry
329 struct sysparam_entry hdr;
330 UINT weight;
331 LOGFONTW val;
332 WCHAR fullname[LF_FACESIZE];
335 struct sysparam_pref_entry
337 struct sysparam_entry hdr;
338 struct sysparam_binary_entry *parent;
339 UINT offset;
340 UINT mask;
343 union sysparam_all_entry
345 struct sysparam_entry hdr;
346 struct sysparam_uint_entry uint;
347 struct sysparam_bool_entry bool;
348 struct sysparam_dword_entry dword;
349 struct sysparam_rgb_entry rgb;
350 struct sysparam_binary_entry bin;
351 struct sysparam_path_entry path;
352 struct sysparam_font_entry font;
353 struct sysparam_pref_entry pref;
356 static UINT system_dpi;
357 static RECT work_area;
359 static HDC display_dc;
360 static pthread_mutex_t display_dc_lock = PTHREAD_MUTEX_INITIALIZER;
362 static HANDLE get_display_device_init_mutex( void )
364 static const WCHAR display_device_initW[] =
365 {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s',
366 '\\','d','i','s','p','l','a','y','_','d','e','v','i','c','e','_','i','n','i','t'};
367 UNICODE_STRING name = { sizeof(display_device_initW), sizeof(display_device_initW),
368 (WCHAR *)display_device_initW };
369 OBJECT_ATTRIBUTES attr;
370 HANDLE mutex;
372 InitializeObjectAttributes( &attr, &name, OBJ_OPENIF, NULL, NULL );
373 if (NtCreateMutant( &mutex, MUTEX_ALL_ACCESS, &attr, FALSE ) < 0) return 0;
374 NtWaitForSingleObject( mutex, FALSE, NULL );
375 return mutex;
378 static void release_display_device_init_mutex( HANDLE mutex )
380 NtReleaseMutant( mutex, NULL );
381 NtClose( mutex );
384 static BOOL read_display_adapter_settings( unsigned int index, struct adapter *info )
386 char buffer[4096];
387 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
388 WCHAR *value_str = (WCHAR *)value->Data;
389 HKEY hkey;
390 DWORD size;
392 if (!enum_key && !(enum_key = reg_open_key( NULL, enum_keyW, sizeof(enum_keyW) )))
393 return FALSE;
395 /* Find adapter */
396 sprintf( buffer, "\\Device\\Video%d", index );
397 size = query_reg_ascii_value( video_key, buffer, value, sizeof(buffer) );
398 if (!size || value->Type != REG_SZ ||
399 value->DataLength <= sizeof("\\Registry\\Machine\\") * sizeof(WCHAR))
400 return FALSE;
402 /* DeviceKey */
403 memcpy( info->dev.device_key, value_str, value->DataLength );
404 info->config_key = info->dev.device_key + sizeof("\\Registry\\Machine\\") - 1;
406 if (!(hkey = reg_open_key( NULL, value_str, value->DataLength - sizeof(WCHAR) )))
407 return FALSE;
409 /* DeviceString */
410 if (query_reg_value( hkey, driver_descW, value, sizeof(buffer) ) && value->Type == REG_SZ)
411 memcpy( info->dev.device_string, value_str, value->DataLength );
412 NtClose( hkey );
414 /* DeviceName */
415 sprintf( buffer, "\\\\.\\DISPLAY%d", index + 1 );
416 asciiz_to_unicode( info->dev.device_name, buffer );
418 if (!(hkey = reg_open_key( config_key, info->config_key,
419 lstrlenW( info->config_key ) * sizeof(WCHAR) )))
420 return FALSE;
422 /* StateFlags */
423 if (query_reg_value( hkey, state_flagsW, value, sizeof(buffer) ) && value->Type == REG_DWORD)
424 info->dev.state_flags = *(const DWORD *)value->Data;
426 /* Interface name */
427 info->dev.interface_name[0] = 0;
429 /* DeviceID */
430 size = query_reg_value( hkey, gpu_idW, value, sizeof(buffer) );
431 NtClose( hkey );
432 if (!size || value->Type != REG_SZ) return FALSE;
434 if (!(hkey = reg_open_key( enum_key, value_str, value->DataLength - sizeof(WCHAR) )))
435 return FALSE;
437 size = query_reg_value( hkey, hardware_idW, value, sizeof(buffer) );
438 NtClose( hkey );
439 if (!size || (value->Type != REG_SZ && value->Type != REG_MULTI_SZ))
440 return FALSE;
442 lstrcpyW( info->dev.device_id, value_str );
443 return TRUE;
446 static unsigned int query_reg_subkey_value( HKEY hkey, const WCHAR *name, unsigned int name_size,
447 KEY_VALUE_PARTIAL_INFORMATION *value, unsigned int size )
449 HKEY subkey;
451 if (!(subkey = reg_open_key( hkey, name, name_size ))) return 0;
452 size = query_reg_value( subkey, NULL, value, size );
453 NtClose( subkey );
454 return size;
457 static BOOL read_monitor_settings( struct adapter *adapter, DWORD index, struct monitor *monitor )
459 char buffer[4096];
460 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
461 WCHAR *device_name, *value_str = (WCHAR *)value->Data, *ptr;
462 HKEY hkey;
463 DWORD size, len;
465 monitor->flags = adapter->id ? 0 : MONITORINFOF_PRIMARY;
467 /* DeviceName */
468 sprintf( buffer, "\\\\.\\DISPLAY%d\\Monitor%d", adapter->id + 1, index );
469 asciiz_to_unicode( monitor->dev.device_name, buffer );
471 if (!(hkey = reg_open_key( config_key, adapter->config_key,
472 lstrlenW( adapter->config_key ) * sizeof(WCHAR) )))
473 return FALSE;
475 /* Interface name */
476 sprintf( buffer, "MonitorID%u", index );
477 size = query_reg_ascii_value( hkey, buffer, value, sizeof(buffer) );
478 NtClose( hkey );
479 if (!size || value->Type != REG_SZ) return FALSE;
480 len = asciiz_to_unicode( monitor->dev.interface_name, "\\\\\?\\" ) / sizeof(WCHAR) - 1;
481 memcpy( monitor->dev.interface_name + len, value_str, value->DataLength - sizeof(WCHAR) );
482 len += value->DataLength / sizeof(WCHAR) - 1;
483 monitor->dev.interface_name[len++] = '#';
484 memcpy( monitor->dev.interface_name + len, guid_devinterface_monitorW,
485 sizeof(guid_devinterface_monitorW) );
487 /* Replace '\\' with '#' after prefix */
488 for (ptr = monitor->dev.interface_name + ARRAYSIZE("\\\\\?\\") - 1; *ptr; ptr++)
489 if (*ptr == '\\') *ptr = '#';
491 if (!(hkey = reg_open_key( enum_key, value_str, value->DataLength - sizeof(WCHAR) )))
492 return FALSE;
494 /* StateFlags, WINE_DEVPROPKEY_MONITOR_STATEFLAGS */
495 size = query_reg_subkey_value( hkey, wine_devpropkey_monitor_stateflagsW,
496 sizeof(wine_devpropkey_monitor_stateflagsW),
497 value, sizeof(buffer) );
498 if (size != sizeof(monitor->dev.state_flags))
500 NtClose( hkey );
501 return FALSE;
503 monitor->dev.state_flags = *(const DWORD *)value->Data;
505 /* rc_monitor, WINE_DEVPROPKEY_MONITOR_RCMONITOR */
506 size = query_reg_subkey_value( hkey, wine_devpropkey_monitor_rcmonitorW,
507 sizeof(wine_devpropkey_monitor_rcmonitorW),
508 value, sizeof(buffer) );
509 if (size != sizeof(monitor->rc_monitor))
511 NtClose( hkey );
512 return FALSE;
514 monitor->rc_monitor = *(const RECT *)value->Data;
516 /* rc_work, WINE_DEVPROPKEY_MONITOR_RCWORK */
517 size = query_reg_subkey_value( hkey, wine_devpropkey_monitor_rcworkW,
518 sizeof(wine_devpropkey_monitor_rcworkW),
519 value, sizeof(buffer) );
520 if (size != sizeof(monitor->rc_work))
522 NtClose( hkey );
523 return FALSE;
525 monitor->rc_work = *(const RECT *)value->Data;
527 /* DeviceString */
528 if (!query_reg_value( hkey, device_descW, value, sizeof(buffer) ) || value->Type != REG_SZ)
530 NtClose( hkey );
531 return FALSE;
533 memcpy( monitor->dev.device_string, value->Data, value->DataLength );
535 /* DeviceKey */
536 if (!query_reg_value( hkey, driverW, value, sizeof(buffer) ) || value->Type != REG_SZ)
538 NtClose( hkey );
539 return FALSE;
541 size = asciiz_to_unicode( monitor->dev.device_key,
542 "\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\" );
543 device_name = &monitor->dev.device_key[size / sizeof(WCHAR) - 1];
544 memcpy( device_name, value_str, value->DataLength );
546 /* DeviceID */
547 if (!query_reg_value( hkey, hardware_idW, value, sizeof(buffer) ) ||
548 (value->Type != REG_SZ && value->Type != REG_MULTI_SZ))
550 NtClose( hkey );
551 return FALSE;
553 size = lstrlenW( value_str );
554 memcpy( monitor->dev.device_id, value_str, size * sizeof(WCHAR) );
555 monitor->dev.device_id[size++] = '\\';
556 lstrcpyW( monitor->dev.device_id + size, device_name );
558 NtClose( hkey );
559 return TRUE;
562 static void reg_empty_key( HKEY root, const char *key_name )
564 char buffer[4096];
565 KEY_NODE_INFORMATION *key = (KEY_NODE_INFORMATION *)buffer;
566 KEY_VALUE_FULL_INFORMATION *value = (KEY_VALUE_FULL_INFORMATION *)buffer;
567 WCHAR bufferW[512];
568 DWORD size;
569 HKEY hkey;
571 if (key_name)
572 hkey = reg_open_key( root, bufferW, asciiz_to_unicode( bufferW, key_name ) - sizeof(WCHAR) );
573 else
574 hkey = root;
576 while (!NtEnumerateKey( hkey, 0, KeyNodeInformation, key, sizeof(buffer), &size ))
577 reg_delete_tree( hkey, key->Name, key->NameLength );
579 while (!NtEnumerateValueKey( hkey, 0, KeyValueFullInformation, value, sizeof(buffer), &size ))
581 UNICODE_STRING name = { value->NameLength, value->NameLength, value->Name };
582 NtDeleteValueKey( hkey, &name );
585 if (hkey != root) NtClose( hkey );
588 static void prepare_devices(void)
590 char buffer[4096];
591 KEY_NODE_INFORMATION *key = (void *)buffer;
592 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
593 WCHAR *value_str = (WCHAR *)value->Data;
594 WCHAR bufferW[128];
595 unsigned i = 0;
596 DWORD size;
597 HKEY hkey, subkey, device_key, prop_key;
599 if (!enum_key) enum_key = reg_create_key( NULL, enum_keyW, sizeof(enum_keyW), 0, NULL );
600 if (!control_key) control_key = reg_create_key( NULL, control_keyW, sizeof(control_keyW), 0, NULL );
601 if (!video_key) video_key = reg_create_key( NULL, devicemap_video_keyW, sizeof(devicemap_video_keyW),
602 REG_OPTION_VOLATILE, NULL );
604 /* delete monitors */
605 reg_empty_key( enum_key, "DISPLAY\\DEFAULT_MONITOR" );
606 sprintf( buffer, "Class\\%s", guid_devclass_monitorA );
607 hkey = reg_create_key( control_key, bufferW, asciiz_to_unicode( bufferW, buffer ) - sizeof(WCHAR),
608 0, NULL );
609 reg_empty_key( hkey, NULL );
610 set_reg_value( hkey, classW, REG_SZ, monitorW, sizeof(monitorW) );
611 NtClose( hkey );
613 /* delete adapters */
614 reg_empty_key( video_key, NULL );
616 /* clean GPUs */
617 sprintf( buffer, "Class\\%s", guid_devclass_displayA );
618 hkey = reg_create_key( control_key, bufferW, asciiz_to_unicode( bufferW, buffer ) - sizeof(WCHAR),
619 0, NULL );
620 reg_empty_key( hkey, NULL );
621 set_reg_value( hkey, classW, REG_SZ, displayW, sizeof(displayW) );
622 NtClose( hkey );
624 hkey = reg_open_key( enum_key, pciW, sizeof(pciW) );
626 /* To preserve GPU GUIDs, mark them as not present and delete them in cleanup_devices if needed. */
627 while (!NtEnumerateKey( hkey, i++, KeyNodeInformation, key, sizeof(buffer), &size ))
629 unsigned int j = 0;
631 if (!(subkey = reg_open_key( hkey, key->Name, key->NameLength ))) continue;
633 while (!NtEnumerateKey( subkey, j++, KeyNodeInformation, key, sizeof(buffer), &size ))
635 if (!(device_key = reg_open_key( subkey, key->Name, key->NameLength ))) continue;
636 size = query_reg_value( device_key, class_guidW, value, sizeof(buffer) );
637 if (size != sizeof(guid_devclass_displayW) || wcscmp( value_str, guid_devclass_displayW ))
639 NtClose( device_key );
640 continue;
643 size = query_reg_value( device_key, class_guidW, value, sizeof(buffer) );
644 if (size == sizeof(guid_devclass_displayW) &&
645 !wcscmp( (const WCHAR *)value->Data, guid_devclass_displayW ) &&
646 (prop_key = reg_create_key( device_key, devpropkey_device_ispresentW,
647 sizeof(devpropkey_device_ispresentW), 0, NULL )))
649 BOOL present = FALSE;
650 set_reg_value( prop_key, NULL, 0xffff0000 | DEVPROP_TYPE_BOOLEAN,
651 &present, sizeof(present) );
652 NtClose( prop_key );
655 NtClose( device_key );
658 NtClose( subkey );
661 NtClose( hkey );
664 static void cleanup_devices(void)
666 char buffer[4096];
667 KEY_NODE_INFORMATION *key = (void *)buffer;
668 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
669 WCHAR bufferW[512], *value_str = (WCHAR *)value->Data;
670 unsigned i = 0;
671 DWORD size;
672 HKEY hkey, subkey, device_key, prop_key;
674 hkey = reg_open_key( enum_key, pciW, sizeof(pciW) );
676 restart:
677 while (!NtEnumerateKey( hkey, i++, KeyNodeInformation, key, sizeof(buffer), &size ))
679 unsigned int j = 0;
681 if (!(subkey = reg_open_key( hkey, key->Name, key->NameLength ))) continue;
683 while (!NtEnumerateKey( subkey, j++, KeyNodeInformation, key, sizeof(buffer), &size ))
685 BOOL present = FALSE;
687 if (!(device_key = reg_open_key( subkey, key->Name, key->NameLength ))) continue;
688 memcpy( bufferW, key->Name, key->NameLength );
689 bufferW[key->NameLength / sizeof(WCHAR)] = 0;
691 size = query_reg_value( device_key, class_guidW, value, sizeof(buffer) );
692 if (size != sizeof(guid_devclass_displayW) || wcscmp( value_str, guid_devclass_displayW ))
694 NtClose( device_key );
695 continue;
698 if ((prop_key = reg_open_key( device_key, devpropkey_device_ispresentW,
699 sizeof(devpropkey_device_ispresentW) )))
701 if (query_reg_value( prop_key, NULL, value, sizeof(buffer) ) == sizeof(BOOL))
702 present = *(const BOOL *)value->Data;
703 NtClose( prop_key );
706 NtClose( device_key );
708 if (!present && reg_delete_tree( subkey, bufferW, lstrlenW( bufferW ) * sizeof(WCHAR) ))
709 goto restart;
712 NtClose( subkey );
715 NtClose( hkey );
718 /* see UuidCreate */
719 static void uuid_create( GUID *uuid )
721 char buf[4096];
722 NtQuerySystemInformation( SystemInterruptInformation, buf, sizeof(buf), NULL );
723 memcpy( uuid, buf, sizeof(*uuid) );
724 uuid->Data3 &= 0x0fff;
725 uuid->Data3 |= (4 << 12);
726 uuid->Data4[0] &= 0x3f;
727 uuid->Data4[0] |= 0x80;
730 #define TICKSPERSEC 10000000
731 #define SECSPERDAY 86400
732 #define DAYSPERQUADRICENTENNIUM (365 * 400 + 97)
733 #define DAYSPERNORMALQUADRENNIUM (365 * 4 + 1)
735 static unsigned int format_date( WCHAR *bufferW, LONGLONG time )
737 int cleaps, years, yearday, months, days;
738 unsigned int day, month, year;
739 char buffer[32];
741 days = time / TICKSPERSEC / SECSPERDAY;
743 /* compute year, month and day of month, see RtlTimeToTimeFields */
744 cleaps = (3 * ((4 * days + 1227) / DAYSPERQUADRICENTENNIUM) + 3) / 4;
745 days += 28188 + cleaps;
746 years = (20 * days - 2442) / (5 * DAYSPERNORMALQUADRENNIUM);
747 yearday = days - (years * DAYSPERNORMALQUADRENNIUM) / 4;
748 months = (64 * yearday) / 1959;
749 if (months < 14)
751 month = months - 1;
752 year = years + 1524;
754 else
756 month = months - 13;
757 year = years + 1525;
759 day = yearday - (1959 * months) / 64 ;
761 sprintf( buffer, "%u-%u-%u", month, day, year );
762 return asciiz_to_unicode( bufferW, buffer );
765 struct device_manager_ctx
767 unsigned int gpu_count;
768 unsigned int adapter_count;
769 unsigned int video_count;
770 unsigned int monitor_count;
771 unsigned int output_count;
772 HANDLE mutex;
773 WCHAR gpuid[128];
774 WCHAR gpu_guid[64];
775 LUID gpu_luid;
776 HKEY adapter_key;
777 BOOL virtual_monitor;
780 static void link_device( const WCHAR *instance, const WCHAR *class )
782 unsigned int instance_len = lstrlenW( instance ), len;
783 unsigned int class_len = lstrlenW( class );
784 WCHAR buffer[MAX_PATH], *ptr;
785 HKEY hkey, subkey;
787 static const WCHAR symbolic_linkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
788 static const WCHAR hashW[] = {'#'};
790 len = asciiz_to_unicode( buffer, "DeviceClasses\\" ) / sizeof(WCHAR) - 1;
791 memcpy( buffer + len, class, class_len * sizeof(WCHAR) );
792 len += class_len;
793 len += asciiz_to_unicode( buffer + len, "\\##?#" ) / sizeof(WCHAR) - 1;
794 memcpy( buffer + len, instance, instance_len * sizeof(WCHAR) );
795 for (ptr = buffer + len; *ptr; ptr++) if (*ptr == '\\') *ptr = '#';
796 len += instance_len;
797 buffer[len++] = '#';
798 memcpy( buffer + len, class, class_len * sizeof(WCHAR) );
799 len += class_len;
800 hkey = reg_create_key( control_key, buffer, len * sizeof(WCHAR), 0, NULL );
802 set_reg_value( hkey, device_instanceW, REG_SZ, instance, (instance_len + 1) * sizeof(WCHAR) );
804 subkey = reg_create_key( hkey, hashW, sizeof(hashW), REG_OPTION_VOLATILE, NULL );
805 NtClose( hkey );
806 hkey = subkey;
808 len = asciiz_to_unicode( buffer, "\\\\?\\" ) / sizeof(WCHAR) - 1;
809 memcpy( buffer + len, instance, (instance_len + 1) * sizeof(WCHAR) );
810 len += instance_len;
811 memcpy( buffer + len, class, (class_len + 1) * sizeof(WCHAR) );
812 len += class_len + 1;
813 for (ptr = buffer + 4; *ptr; ptr++) if (*ptr == '\\') *ptr = '#';
814 set_reg_value( hkey, symbolic_linkW, REG_SZ, buffer, len * sizeof(WCHAR) );
816 if ((subkey = reg_create_key( hkey, controlW, sizeof(controlW), REG_OPTION_VOLATILE, NULL )))
818 const DWORD linked = 1;
819 set_reg_value( subkey, linkedW, REG_DWORD, &linked, sizeof(linked) );
820 NtClose( subkey );
824 static void add_gpu( const struct gdi_gpu *gpu, void *param )
826 struct device_manager_ctx *ctx = param;
827 const WCHAR *desc;
828 char buffer[4096];
829 WCHAR bufferW[512];
830 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
831 unsigned int gpu_index, size;
832 HKEY hkey, subkey;
833 LARGE_INTEGER ft;
835 static const BOOL present = TRUE;
836 static const WCHAR wine_adapterW[] = {'W','i','n','e',' ','A','d','a','p','t','e','r',0};
837 static const WCHAR video_idW[] = {'V','i','d','e','o','I','D',0};
838 static const WCHAR driver_date_dataW[] =
839 {'D','r','i','v','e','r','D','a','t','e','D','a','t','a',0};
840 static const WCHAR adapter_stringW[] =
841 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n',
842 '.','A','d','a','p','t','e','r','S','t','r','i','n','g',0};
843 static const WCHAR bios_stringW[] =
844 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n','.',
845 'B','i','o','s','S','t','r','i','n','g',0};
846 static const WCHAR chip_typeW[] =
847 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n','.',
848 'C','h','i','p','T','y','p','e',0};
849 static const WCHAR dac_typeW[] =
850 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n','.',
851 'D','a','c','T','y','p','e',0};
852 static const WCHAR ramdacW[] =
853 {'I','n','t','e','r','g','r','a','t','e','d',' ','R','A','M','D','A','C',0};
854 static const WCHAR driver_dateW[] = {'D','r','i','v','e','r','D','a','t','e',0};
856 TRACE( "%s %04X %04X %08X %02X\n", debugstr_w(gpu->name),
857 gpu->vendor_id, gpu->device_id, gpu->subsys_id, gpu->revision_id );
859 gpu_index = ctx->gpu_count++;
860 ctx->adapter_count = 0;
861 ctx->monitor_count = 0;
863 if (!enum_key && !(enum_key = reg_create_key( NULL, enum_keyW, sizeof(enum_keyW), 0, NULL )))
864 return;
866 if (!ctx->mutex)
868 ctx->mutex = get_display_device_init_mutex();
869 pthread_mutex_lock( &display_lock );
870 prepare_devices();
873 sprintf( buffer, "PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X\\%08X",
874 gpu->vendor_id, gpu->device_id, gpu->subsys_id, gpu->revision_id, gpu_index );
875 size = asciiz_to_unicode( ctx->gpuid, buffer );
876 if (!(hkey = reg_create_key( enum_key, ctx->gpuid, size - sizeof(WCHAR), 0, NULL ))) return;
878 set_reg_value( hkey, classW, REG_SZ, displayW, sizeof(displayW) );
879 set_reg_value( hkey, class_guidW, REG_SZ, guid_devclass_displayW,
880 sizeof(guid_devclass_displayW) );
881 sprintf( buffer, "%s\\%04X", guid_devclass_displayA, gpu_index );
882 set_reg_value( hkey, driverW, REG_SZ, bufferW, asciiz_to_unicode( bufferW, buffer ));
884 sprintf( buffer, "PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X",
885 gpu->vendor_id, gpu->device_id, gpu->subsys_id, gpu->revision_id );
886 size = asciiz_to_unicode( bufferW, buffer );
887 bufferW[size / sizeof(WCHAR)] = 0; /* for REG_MULTI_SZ */
888 set_reg_value( hkey, hardware_idW, REG_MULTI_SZ, bufferW, size + sizeof(WCHAR) );
890 desc = gpu->name;
891 if (!desc[0]) desc = wine_adapterW;
892 set_reg_value( hkey, device_descW, REG_SZ, desc, (lstrlenW( desc ) + 1) * sizeof(WCHAR) );
894 if ((subkey = reg_create_key( hkey, device_parametersW, sizeof(device_parametersW), 0, NULL )))
896 if (!query_reg_value( subkey, video_idW, value, sizeof(buffer) ))
898 GUID guid;
899 uuid_create( &guid );
900 sprintf( buffer, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
901 guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2],
902 guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7] );
903 size = asciiz_to_unicode( ctx->gpu_guid, buffer );
904 TRACE( "created guid %s\n", debugstr_w(ctx->gpu_guid) );
905 set_reg_value( subkey, video_idW, REG_SZ, ctx->gpu_guid, size );
907 else
909 memcpy( ctx->gpu_guid, value->Data, value->DataLength );
910 TRACE( "got guid %s\n", debugstr_w(ctx->gpu_guid) );
912 NtClose( subkey );
915 if ((subkey = reg_create_key( hkey, devpropkey_gpu_vulkan_uuidW,
916 sizeof(devpropkey_gpu_vulkan_uuidW), 0, NULL )))
918 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_GUID,
919 &gpu->vulkan_uuid, sizeof(gpu->vulkan_uuid) );
920 NtClose( subkey );
923 if ((subkey = reg_create_key( hkey, devpropkey_device_ispresentW,
924 sizeof(devpropkey_device_ispresentW), 0, NULL )))
926 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_BOOLEAN,
927 &present, sizeof(present) );
928 NtClose( subkey );
931 if ((subkey = reg_create_key( hkey, devpropkey_gpu_luidW, sizeof(devpropkey_gpu_luidW), 0, NULL )))
933 if (query_reg_value( subkey, NULL, value, sizeof(buffer) ) != sizeof(LUID))
935 NtAllocateLocallyUniqueId( &ctx->gpu_luid );
936 TRACE("allocated luid %08x%08x\n", ctx->gpu_luid.HighPart, ctx->gpu_luid.LowPart );
937 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_UINT64,
938 &ctx->gpu_luid, sizeof(ctx->gpu_luid) );
940 else
942 memcpy( &ctx->gpu_luid, value->Data, sizeof(ctx->gpu_luid) );
943 TRACE("got luid %08x%08x\n", ctx->gpu_luid.HighPart, ctx->gpu_luid.LowPart );
945 NtClose( subkey );
948 NtClose( hkey );
950 sprintf( buffer, "Class\\%s\\%04X", guid_devclass_displayA, gpu_index );
951 hkey = reg_create_key( control_key, bufferW,
952 asciiz_to_unicode( bufferW, buffer ) - sizeof(WCHAR), 0, NULL );
954 NtQuerySystemTime( &ft );
955 set_reg_value( hkey, driver_dateW, REG_SZ, bufferW, format_date( bufferW, ft.QuadPart ));
957 set_reg_value( hkey, driver_date_dataW, REG_BINARY, &ft, sizeof(ft) );
959 size = (lstrlenW( desc ) + 1) * sizeof(WCHAR);
960 set_reg_value( hkey, driver_descW, REG_SZ, desc, size );
961 set_reg_value( hkey, adapter_stringW, REG_BINARY, desc, size );
962 set_reg_value( hkey, bios_stringW, REG_BINARY, desc, size );
963 set_reg_value( hkey, chip_typeW, REG_BINARY, desc, size );
964 set_reg_value( hkey, dac_typeW, REG_BINARY, ramdacW, sizeof(ramdacW) );
966 NtClose( hkey );
968 link_device( ctx->gpuid, guid_devinterface_display_adapterW );
969 link_device( ctx->gpuid, guid_display_device_arrivalW );
972 static void add_adapter( const struct gdi_adapter *adapter, void *param )
974 struct device_manager_ctx *ctx = param;
975 unsigned int adapter_index, video_index, len;
976 char name[64], buffer[MAX_PATH];
977 WCHAR nameW[64], bufferW[MAX_PATH];
978 HKEY hkey;
980 TRACE( "\n" );
982 if (!ctx->gpu_count)
984 static const struct gdi_gpu default_gpu;
985 TRACE( "adding default fake GPU\n" );
986 add_gpu( &default_gpu, ctx );
989 if (ctx->adapter_key)
991 NtClose( ctx->adapter_key );
992 ctx->adapter_key = NULL;
995 adapter_index = ctx->adapter_count++;
996 video_index = ctx->video_count++;
997 ctx->monitor_count = 0;
999 len = asciiz_to_unicode( bufferW, "\\Registry\\Machine\\System\\CurrentControlSet\\"
1000 "Control\\Video\\" ) / sizeof(WCHAR) - 1;
1001 lstrcpyW( bufferW + len, ctx->gpu_guid );
1002 len += lstrlenW( bufferW + len );
1003 sprintf( buffer, "\\%04x", adapter_index );
1004 len += asciiz_to_unicode( bufferW + len, buffer ) / sizeof(WCHAR) - 1;
1005 hkey = reg_create_key( NULL, bufferW, len * sizeof(WCHAR),
1006 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK, NULL );
1007 if (!hkey) hkey = reg_create_key( NULL, bufferW, len * sizeof(WCHAR),
1008 REG_OPTION_VOLATILE | REG_OPTION_OPEN_LINK, NULL );
1010 sprintf( name, "\\Device\\Video%u", video_index );
1011 asciiz_to_unicode( nameW, name );
1012 set_reg_value( video_key, nameW, REG_SZ, bufferW, (lstrlenW( bufferW ) + 1) * sizeof(WCHAR) );
1014 if (hkey)
1016 sprintf( buffer, "\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\"
1017 "%s\\%04X", guid_devclass_displayA, ctx->gpu_count - 1 );
1018 len = asciiz_to_unicode( bufferW, buffer ) - sizeof(WCHAR);
1019 set_reg_value( hkey, symbolic_link_valueW, REG_LINK, bufferW, len );
1020 NtClose( hkey );
1022 else ERR( "failed to create link key\n" );
1024 /* Following information is Wine specific, it doesn't really exist on Windows. */
1025 len = asciiz_to_unicode( bufferW, "System\\CurrentControlSet\\Control\\Video\\" )
1026 / sizeof(WCHAR) - 1;
1027 lstrcpyW( bufferW + len, ctx->gpu_guid );
1028 len += lstrlenW( bufferW + len );
1029 sprintf( buffer, "\\%04x", adapter_index );
1030 len += asciiz_to_unicode( bufferW + len, buffer ) / sizeof(WCHAR) - 1;
1031 ctx->adapter_key = reg_create_key( config_key, bufferW, len * sizeof(WCHAR),
1032 REG_OPTION_VOLATILE, NULL );
1034 set_reg_value( ctx->adapter_key, gpu_idW, REG_SZ, ctx->gpuid,
1035 (lstrlenW( ctx->gpuid ) + 1) * sizeof(WCHAR) );
1036 set_reg_value( ctx->adapter_key, state_flagsW, REG_DWORD, &adapter->state_flags,
1037 sizeof(adapter->state_flags) );
1040 static void add_monitor( const struct gdi_monitor *monitor, void *param )
1042 struct device_manager_ctx *ctx = param;
1043 char buffer[MAX_PATH], instance[64];
1044 unsigned int monitor_index, output_index;
1045 WCHAR bufferW[MAX_PATH];
1046 HKEY hkey, subkey;
1048 static const WCHAR default_monitorW[] =
1049 {'M','O','N','I','T','O','R','\\','D','e','f','a','u','l','t','_','M','o','n','i','t','o','r',0,0};
1051 if (!monitor)
1053 ctx->virtual_monitor = TRUE;
1054 return;
1057 TRACE( "%s %s %s\n", debugstr_w(monitor->name), wine_dbgstr_rect(&monitor->rc_monitor),
1058 wine_dbgstr_rect(&monitor->rc_work) );
1060 if (!ctx->adapter_count)
1062 static const struct gdi_adapter default_adapter =
1064 .state_flags = DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_PRIMARY_DEVICE |
1065 DISPLAY_DEVICE_VGA_COMPATIBLE,
1067 TRACE( "adding default fake adapter\n" );
1068 add_adapter( &default_adapter, ctx );
1071 monitor_index = ctx->monitor_count++;
1072 output_index = ctx->output_count++;
1074 sprintf( buffer, "MonitorID%u", monitor_index );
1075 sprintf( instance, "DISPLAY\\Default_Monitor\\%04X&%04X", ctx->video_count - 1, monitor_index );
1076 set_reg_ascii_value( ctx->adapter_key, buffer, instance );
1078 hkey = reg_create_key( enum_key, bufferW, asciiz_to_unicode( bufferW, instance ) - sizeof(WCHAR),
1079 0, NULL );
1080 if (!hkey) return;
1082 link_device( bufferW, guid_devinterface_monitorW );
1084 lstrcpyW( bufferW, monitor->name );
1085 if (!bufferW[0]) asciiz_to_unicode( bufferW, "Generic Non-PnP Monitor" );
1086 set_reg_value( hkey, device_descW, REG_SZ, bufferW, (lstrlenW( bufferW ) + 1) * sizeof(WCHAR) );
1088 set_reg_value( hkey, classW, REG_SZ, monitorW, sizeof(monitorW) );
1089 sprintf( buffer, "%s\\%04X", guid_devclass_monitorA, output_index );
1090 set_reg_ascii_value( hkey, "Driver", buffer );
1091 set_reg_value( hkey, class_guidW, REG_SZ, guid_devclass_monitorW, sizeof(guid_devclass_monitorW) );
1092 set_reg_value( hkey, hardware_idW, REG_MULTI_SZ, default_monitorW, sizeof(default_monitorW) );
1094 if ((subkey = reg_create_key( hkey, device_parametersW, sizeof(device_parametersW), 0, NULL )))
1096 static const WCHAR edidW[] = {'E','D','I','D',0};
1097 set_reg_value( subkey, edidW, REG_BINARY, monitor->edid, monitor->edid_len );
1098 NtClose( subkey );
1101 /* StateFlags */
1102 if ((subkey = reg_create_key( hkey, wine_devpropkey_monitor_stateflagsW,
1103 sizeof(wine_devpropkey_monitor_stateflagsW), 0, NULL )))
1105 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_UINT32, &monitor->state_flags,
1106 sizeof(monitor->state_flags) );
1107 NtClose( subkey );
1110 /* WINE_DEVPROPKEY_MONITOR_RCMONITOR */
1111 if ((subkey = reg_create_key( hkey, wine_devpropkey_monitor_rcmonitorW,
1112 sizeof(wine_devpropkey_monitor_rcmonitorW), 0, NULL )))
1114 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_BINARY, &monitor->rc_monitor,
1115 sizeof(monitor->rc_monitor) );
1116 NtClose( subkey );
1119 /* WINE_DEVPROPKEY_MONITOR_RCWORK */
1120 if ((subkey = reg_create_key( hkey, wine_devpropkey_monitor_rcworkW,
1121 sizeof(wine_devpropkey_monitor_rcworkW), 0, NULL )))
1123 TRACE( "rc_work %s\n", wine_dbgstr_rect(&monitor->rc_work) );
1124 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_BINARY, &monitor->rc_work,
1125 sizeof(monitor->rc_work) );
1126 NtClose( subkey );
1129 /* WINE_DEVPROPKEY_MONITOR_ADAPTERNAME */
1130 if ((subkey = reg_create_key( hkey, wine_devpropkey_monitor_adapternameW,
1131 sizeof(wine_devpropkey_monitor_adapternameW), 0, NULL )))
1133 sprintf( buffer, "\\\\.\\DISPLAY%u", ctx->video_count );
1134 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_STRING, bufferW,
1135 asciiz_to_unicode( bufferW, buffer ));
1136 NtClose( subkey );
1139 /* DEVPROPKEY_MONITOR_GPU_LUID */
1140 if ((subkey = reg_create_key( hkey, devpropkey_monitor_gpu_luidW,
1141 sizeof(devpropkey_monitor_gpu_luidW), 0, NULL )))
1143 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_INT64,
1144 &ctx->gpu_luid, sizeof(ctx->gpu_luid) );
1145 NtClose( subkey );
1148 /* DEVPROPKEY_MONITOR_OUTPUT_ID */
1149 if ((subkey = reg_create_key( hkey, devpropkey_monitor_output_idW,
1150 sizeof(devpropkey_monitor_output_idW), 0, NULL )))
1152 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_UINT32,
1153 &output_index, sizeof(output_index) );
1154 NtClose( subkey );
1157 NtClose( hkey );
1159 sprintf( buffer, "Class\\%s\\%04X", guid_devclass_monitorA, output_index );
1160 hkey = reg_create_key( control_key, bufferW,
1161 asciiz_to_unicode( bufferW, buffer ) - sizeof(WCHAR), 0, NULL );
1162 if (hkey) NtClose( hkey );
1165 static const struct gdi_device_manager device_manager =
1167 add_gpu,
1168 add_adapter,
1169 add_monitor,
1172 static void release_display_manager_ctx( struct device_manager_ctx *ctx )
1174 if (ctx->mutex)
1176 pthread_mutex_unlock( &display_lock );
1177 release_display_device_init_mutex( ctx->mutex );
1179 if (ctx->adapter_key)
1181 NtClose( ctx->adapter_key );
1182 last_query_display_time = 0;
1184 if (ctx->gpu_count) cleanup_devices();
1187 static void clear_display_devices(void)
1189 struct adapter *adapter;
1190 struct monitor *monitor;
1192 if (list_head( &monitors ) == &virtual_monitor.entry)
1194 list_init( &monitors );
1195 return;
1198 while (!list_empty( &monitors ))
1200 monitor = LIST_ENTRY( list_head( &monitors ), struct monitor, entry );
1201 list_remove( &monitor->entry );
1202 free( monitor );
1205 while (!list_empty( &adapters ))
1207 adapter = LIST_ENTRY( list_head( &adapters ), struct adapter, entry );
1208 list_remove( &adapter->entry );
1209 free( adapter );
1213 static BOOL update_display_cache_from_registry(void)
1215 DWORD adapter_id, monitor_id, monitor_count = 0, size;
1216 KEY_FULL_INFORMATION key;
1217 struct adapter *adapter;
1218 struct monitor *monitor;
1219 HANDLE mutex = NULL;
1220 NTSTATUS status;
1221 BOOL ret;
1223 /* If user driver did initialize the registry, then exit */
1224 if (!video_key && !(video_key = reg_open_key( NULL, devicemap_video_keyW,
1225 sizeof(devicemap_video_keyW) )))
1226 return FALSE;
1228 status = NtQueryKey( video_key, KeyFullInformation, &key, sizeof(key), &size );
1229 if (status && status != STATUS_BUFFER_OVERFLOW)
1230 return FALSE;
1232 if (key.LastWriteTime.QuadPart <= last_query_display_time) return TRUE;
1234 mutex = get_display_device_init_mutex();
1235 pthread_mutex_lock( &display_lock );
1237 clear_display_devices();
1239 for (adapter_id = 0;; adapter_id++)
1241 if (!(adapter = calloc( 1, sizeof(*adapter) ))) break;
1242 adapter->id = adapter_id;
1244 if (!read_display_adapter_settings( adapter_id, adapter ))
1246 free( adapter );
1247 break;
1250 list_add_tail( &adapters, &adapter->entry );
1251 for (monitor_id = 0;; monitor_id++)
1253 if (!(monitor = calloc( 1, sizeof(*monitor) ))) break;
1254 monitor->id = monitor_id;
1255 monitor->adapter = adapter;
1257 if (!read_monitor_settings( adapter, monitor_id, monitor ))
1259 free( monitor );
1260 break;
1263 monitor->handle = UlongToHandle( ++monitor_count );
1264 list_add_tail( &monitors, &monitor->entry );
1268 if ((ret = !list_empty( &adapters ) && !list_empty( &monitors )))
1269 last_query_display_time = key.LastWriteTime.QuadPart;
1270 pthread_mutex_unlock( &display_lock );
1271 release_display_device_init_mutex( mutex );
1272 return ret;
1275 static BOOL update_display_cache(void)
1277 struct device_manager_ctx ctx = { 0 };
1279 user_driver->pUpdateDisplayDevices( &device_manager, FALSE, &ctx );
1280 release_display_manager_ctx( &ctx );
1281 if (ctx.virtual_monitor)
1283 clear_display_devices();
1284 list_add_tail( &monitors, &virtual_monitor.entry );
1285 return TRUE;
1288 if (update_display_cache_from_registry()) return TRUE;
1289 if (ctx.gpu_count)
1291 ERR( "driver reported devices, but we failed to read them\n" );
1292 return FALSE;
1295 user_driver->pUpdateDisplayDevices( &device_manager, TRUE, &ctx );
1296 release_display_manager_ctx( &ctx );
1298 if (!update_display_cache_from_registry())
1300 ERR( "failed to read display config\n" );
1301 return FALSE;
1304 return TRUE;
1307 static BOOL lock_display_devices(void)
1309 if (!update_display_cache()) return FALSE;
1310 pthread_mutex_lock( &display_lock );
1311 return TRUE;
1314 static void unlock_display_devices(void)
1316 pthread_mutex_unlock( &display_lock );
1319 HDC get_display_dc(void)
1321 pthread_mutex_lock( &display_dc_lock );
1322 if (!display_dc)
1324 HDC dc;
1326 pthread_mutex_unlock( &display_dc_lock );
1327 dc = NtGdiOpenDCW( NULL, NULL, NULL, 0, TRUE, NULL, NULL, NULL );
1328 pthread_mutex_lock( &display_dc_lock );
1329 if (display_dc)
1330 NtGdiDeleteObjectApp( dc );
1331 else
1332 display_dc = dc;
1334 return display_dc;
1337 void release_display_dc( HDC hdc )
1339 pthread_mutex_unlock( &display_dc_lock );
1342 /**********************************************************************
1343 * get_monitor_dpi
1345 static UINT get_monitor_dpi( HMONITOR monitor )
1347 /* FIXME: use the monitor DPI instead */
1348 return system_dpi;
1351 /**********************************************************************
1352 * get_thread_dpi_awareness
1354 static DPI_AWARENESS get_thread_dpi_awareness(void)
1356 struct user_thread_info *info = get_user_thread_info();
1357 ULONG_PTR context = info->dpi_awareness;
1359 if (!context) context = NtUserGetProcessDpiAwarenessContext( NULL );
1361 switch (context)
1363 case 0x10:
1364 case 0x11:
1365 case 0x12:
1366 case 0x80000010:
1367 case 0x80000011:
1368 case 0x80000012:
1369 return context & 3;
1370 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE:
1371 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE:
1372 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE:
1373 return ~context;
1374 default:
1375 return DPI_AWARENESS_INVALID;
1379 /**********************************************************************
1380 * get_thread_dpi
1382 static UINT get_thread_dpi(void)
1384 switch (get_thread_dpi_awareness())
1386 case DPI_AWARENESS_UNAWARE: return USER_DEFAULT_SCREEN_DPI;
1387 case DPI_AWARENESS_SYSTEM_AWARE: return system_dpi;
1388 default: return 0; /* no scaling */
1392 /* see GetDpiForSystem */
1393 UINT get_system_dpi(void)
1395 if (get_thread_dpi_awareness() == DPI_AWARENESS_UNAWARE) return USER_DEFAULT_SCREEN_DPI;
1396 return system_dpi;
1399 /**********************************************************************
1400 * map_dpi_rect
1402 RECT map_dpi_rect( RECT rect, UINT dpi_from, UINT dpi_to )
1404 if (dpi_from && dpi_to && dpi_from != dpi_to)
1406 rect.left = muldiv( rect.left, dpi_to, dpi_from );
1407 rect.top = muldiv( rect.top, dpi_to, dpi_from );
1408 rect.right = muldiv( rect.right, dpi_to, dpi_from );
1409 rect.bottom = muldiv( rect.bottom, dpi_to, dpi_from );
1411 return rect;
1414 /* map value from system dpi to standard 96 dpi for storing in the registry */
1415 static int map_from_system_dpi( int val )
1417 return muldiv( val, USER_DEFAULT_SCREEN_DPI, get_system_dpi() );
1420 /* map value from 96 dpi to system or custom dpi */
1421 static int map_to_dpi( int val, UINT dpi )
1423 if (!dpi) dpi = get_system_dpi();
1424 return muldiv( val, dpi, USER_DEFAULT_SCREEN_DPI );
1427 RECT get_virtual_screen_rect( UINT dpi )
1429 struct monitor *monitor;
1430 RECT rect = {0};
1432 if (!lock_display_devices()) return rect;
1434 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
1436 union_rect( &rect, &rect, &monitor->rc_monitor );
1439 unlock_display_devices();
1441 if (dpi) rect = map_dpi_rect( rect, system_dpi, dpi );
1442 return rect;
1445 RECT get_display_rect( const WCHAR *display )
1447 struct monitor *monitor;
1448 RECT rect = {0};
1450 if (!lock_display_devices()) return rect;
1452 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
1454 if (!monitor->adapter || wcsicmp( monitor->adapter->dev.device_name, display )) continue;
1455 rect = monitor->rc_monitor;
1456 break;
1459 unlock_display_devices();
1460 return map_dpi_rect( rect, system_dpi, get_thread_dpi() );
1463 static RECT get_primary_monitor_rect(void)
1465 struct monitor *monitor;
1466 RECT rect = {0};
1468 if (!lock_display_devices()) return rect;
1470 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
1472 if (!(monitor->flags & MONITORINFOF_PRIMARY)) continue;
1473 rect = monitor->rc_monitor;
1474 break;
1477 unlock_display_devices();
1478 return map_dpi_rect( rect, system_dpi, get_thread_dpi() );
1481 /**********************************************************************
1482 * NtUserGetDisplayConfigBufferSizes (win32u.@)
1484 LONG WINAPI NtUserGetDisplayConfigBufferSizes( UINT32 flags, UINT32 *num_path_info,
1485 UINT32 *num_mode_info )
1487 struct monitor *monitor;
1488 UINT32 count = 0;
1490 TRACE( "(0x%x %p %p)\n", flags, num_path_info, num_mode_info );
1492 if (!num_path_info || !num_mode_info)
1493 return ERROR_INVALID_PARAMETER;
1495 *num_path_info = 0;
1497 switch (flags)
1499 case QDC_ALL_PATHS:
1500 case QDC_ONLY_ACTIVE_PATHS:
1501 case QDC_DATABASE_CURRENT:
1502 break;
1503 default:
1504 return ERROR_INVALID_PARAMETER;
1507 /* FIXME: semi-stub */
1508 if (flags != QDC_ONLY_ACTIVE_PATHS)
1509 FIXME( "only returning active paths\n" );
1511 if (lock_display_devices())
1513 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
1515 if (!(monitor->dev.state_flags & DISPLAY_DEVICE_ACTIVE))
1516 continue;
1517 count++;
1519 unlock_display_devices();
1522 *num_path_info = count;
1523 *num_mode_info = count * 2;
1524 TRACE( "returning %u paths %u modes\n", *num_path_info, *num_mode_info );
1525 return ERROR_SUCCESS;
1528 static struct adapter *find_adapter( UNICODE_STRING *name )
1530 struct adapter *adapter;
1532 LIST_FOR_EACH_ENTRY(adapter, &adapters, struct adapter, entry)
1534 if (!name || !name->Length) return adapter; /* use primary adapter */
1535 if (!wcsnicmp( name->Buffer, adapter->dev.device_name, name->Length / sizeof(WCHAR) ) &&
1536 !adapter->dev.device_name[name->Length / sizeof(WCHAR)])
1537 return adapter;
1539 return NULL;
1542 /***********************************************************************
1543 * NtUserEnumDisplayDevices (win32u.@)
1545 NTSTATUS WINAPI NtUserEnumDisplayDevices( UNICODE_STRING *device, DWORD index,
1546 DISPLAY_DEVICEW *info, DWORD flags )
1548 struct display_device *found = NULL;
1549 struct adapter *adapter;
1550 struct monitor *monitor;
1552 TRACE( "%s %u %p %#x\n", debugstr_us( device ), index, info, flags );
1554 if (!info || !info->cb) return STATUS_UNSUCCESSFUL;
1556 if (!lock_display_devices()) return STATUS_UNSUCCESSFUL;
1558 if (!device || !device->Length)
1560 /* Enumerate adapters */
1561 LIST_FOR_EACH_ENTRY(adapter, &adapters, struct adapter, entry)
1563 if (index == adapter->id)
1565 found = &adapter->dev;
1566 break;
1570 else if ((adapter = find_adapter( device )))
1572 /* Enumerate monitors */
1573 LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry)
1575 if (monitor->adapter == adapter && index == monitor->id)
1577 found = &monitor->dev;
1578 break;
1583 if (found)
1585 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceName) + sizeof(info->DeviceName))
1586 lstrcpyW( info->DeviceName, found->device_name );
1587 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceString) + sizeof(info->DeviceString))
1588 lstrcpyW( info->DeviceString, found->device_string );
1589 if (info->cb >= offsetof(DISPLAY_DEVICEW, StateFlags) + sizeof(info->StateFlags))
1590 info->StateFlags = found->state_flags;
1591 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->DeviceID))
1592 lstrcpyW( info->DeviceID, (flags & EDD_GET_DEVICE_INTERFACE_NAME)
1593 ? found->interface_name : found->device_id );
1594 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(info->DeviceKey))
1595 lstrcpyW( info->DeviceKey, found->device_key );
1597 unlock_display_devices();
1598 return found ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
1601 #define _X_FIELD(prefix, bits) \
1602 if ((fields) & prefix##_##bits) \
1604 p += sprintf( p, "%s%s", first ? "" : ",", #bits ); \
1605 first = FALSE; \
1608 static const char *_CDS_flags( DWORD fields )
1610 BOOL first = TRUE;
1611 CHAR buf[128];
1612 CHAR *p = buf;
1614 _X_FIELD(CDS, UPDATEREGISTRY)
1615 _X_FIELD(CDS, TEST)
1616 _X_FIELD(CDS, FULLSCREEN)
1617 _X_FIELD(CDS, GLOBAL)
1618 _X_FIELD(CDS, SET_PRIMARY)
1619 _X_FIELD(CDS, VIDEOPARAMETERS)
1620 _X_FIELD(CDS, ENABLE_UNSAFE_MODES)
1621 _X_FIELD(CDS, DISABLE_UNSAFE_MODES)
1622 _X_FIELD(CDS, RESET)
1623 _X_FIELD(CDS, RESET_EX)
1624 _X_FIELD(CDS, NORESET)
1626 *p = 0;
1627 return wine_dbg_sprintf( "%s", buf );
1630 static const char *_DM_fields( DWORD fields )
1632 BOOL first = TRUE;
1633 CHAR buf[128];
1634 CHAR *p = buf;
1636 _X_FIELD(DM, BITSPERPEL)
1637 _X_FIELD(DM, PELSWIDTH)
1638 _X_FIELD(DM, PELSHEIGHT)
1639 _X_FIELD(DM, DISPLAYFLAGS)
1640 _X_FIELD(DM, DISPLAYFREQUENCY)
1641 _X_FIELD(DM, POSITION)
1642 _X_FIELD(DM, DISPLAYORIENTATION)
1644 *p = 0;
1645 return wine_dbg_sprintf( "%s", buf );
1648 #undef _X_FIELD
1650 static void trace_devmode( const DEVMODEW *devmode )
1652 TRACE( "dmFields=%s ", _DM_fields(devmode->dmFields) );
1653 if (devmode->dmFields & DM_BITSPERPEL)
1654 TRACE( "dmBitsPerPel=%u ", devmode->dmBitsPerPel );
1655 if (devmode->dmFields & DM_PELSWIDTH)
1656 TRACE( "dmPelsWidth=%u ", devmode->dmPelsWidth );
1657 if (devmode->dmFields & DM_PELSHEIGHT)
1658 TRACE( "dmPelsHeight=%u ", devmode->dmPelsHeight );
1659 if (devmode->dmFields & DM_DISPLAYFREQUENCY)
1660 TRACE( "dmDisplayFrequency=%u ", devmode->dmDisplayFrequency );
1661 if (devmode->dmFields & DM_POSITION)
1662 TRACE( "dmPosition=(%d,%d) ", devmode->dmPosition.x, devmode->dmPosition.y );
1663 if (devmode->dmFields & DM_DISPLAYFLAGS)
1664 TRACE( "dmDisplayFlags=%#x ", devmode->dmDisplayFlags );
1665 if (devmode->dmFields & DM_DISPLAYORIENTATION)
1666 TRACE( "dmDisplayOrientation=%u ", devmode->dmDisplayOrientation );
1667 TRACE("\n");
1670 static BOOL is_detached_mode( const DEVMODEW *mode )
1672 return mode->dmFields & DM_POSITION &&
1673 mode->dmFields & DM_PELSWIDTH &&
1674 mode->dmFields & DM_PELSHEIGHT &&
1675 mode->dmPelsWidth == 0 &&
1676 mode->dmPelsHeight == 0;
1679 /***********************************************************************
1680 * NtUserChangeDisplaySettingsExW (win32u.@)
1682 LONG WINAPI NtUserChangeDisplaySettings( UNICODE_STRING *devname, DEVMODEW *devmode, HWND hwnd,
1683 DWORD flags, void *lparam )
1685 WCHAR device_name[CCHDEVICENAME];
1686 struct adapter *adapter;
1687 BOOL def_mode = TRUE;
1688 DEVMODEW dm;
1689 LONG ret;
1691 TRACE( "%s %p %p %#x %p\n", debugstr_us(devname), devmode, hwnd, flags, lparam );
1692 TRACE( "flags=%s\n", _CDS_flags(flags) );
1694 if ((!devname || !devname->Length) && !devmode)
1696 ret = user_driver->pChangeDisplaySettingsEx( NULL, NULL, hwnd, flags, lparam );
1697 if (ret != DISP_CHANGE_SUCCESSFUL)
1698 ERR( "Restoring all displays to their registry settings returned %d.\n", ret );
1699 return ret;
1702 if (!lock_display_devices()) return DISP_CHANGE_FAILED;
1703 if ((adapter = find_adapter( devname ))) lstrcpyW( device_name, adapter->dev.device_name );
1704 unlock_display_devices();
1705 if (!adapter)
1707 WARN( "Invalid device name %s.\n", debugstr_us(devname) );
1708 return DISP_CHANGE_BADPARAM;
1711 if (devmode)
1713 trace_devmode( devmode );
1715 if (devmode->dmSize < FIELD_OFFSET(DEVMODEW, dmICMMethod))
1716 return DISP_CHANGE_BADMODE;
1718 if (is_detached_mode(devmode) ||
1719 ((devmode->dmFields & DM_BITSPERPEL) && devmode->dmBitsPerPel) ||
1720 ((devmode->dmFields & DM_PELSWIDTH) && devmode->dmPelsWidth) ||
1721 ((devmode->dmFields & DM_PELSHEIGHT) && devmode->dmPelsHeight) ||
1722 ((devmode->dmFields & DM_DISPLAYFREQUENCY) && devmode->dmDisplayFrequency))
1723 def_mode = FALSE;
1726 if (def_mode)
1728 memset( &dm, 0, sizeof(dm) );
1729 dm.dmSize = sizeof(dm);
1730 if (!NtUserEnumDisplaySettings( devname, ENUM_REGISTRY_SETTINGS, &dm, 0 ))
1732 ERR( "Default mode not found!\n" );
1733 return DISP_CHANGE_BADMODE;
1736 TRACE( "Return to original display mode\n" );
1737 devmode = &dm;
1740 if ((devmode->dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != (DM_PELSWIDTH | DM_PELSHEIGHT))
1742 WARN( "devmode doesn't specify the resolution: %#x\n", devmode->dmFields );
1743 return DISP_CHANGE_BADMODE;
1746 if (!is_detached_mode(devmode) && (!devmode->dmPelsWidth || !devmode->dmPelsHeight))
1748 memset(&dm, 0, sizeof(dm));
1749 dm.dmSize = sizeof(dm);
1750 if (!NtUserEnumDisplaySettings( devname, ENUM_CURRENT_SETTINGS, &dm, 0 ))
1752 ERR( "Current mode not found!\n" );
1753 return DISP_CHANGE_BADMODE;
1756 if (!devmode->dmPelsWidth)
1757 devmode->dmPelsWidth = dm.dmPelsWidth;
1758 if (!devmode->dmPelsHeight)
1759 devmode->dmPelsHeight = dm.dmPelsHeight;
1762 ret = user_driver->pChangeDisplaySettingsEx( device_name, devmode, hwnd, flags, lparam );
1763 if (ret != DISP_CHANGE_SUCCESSFUL)
1764 ERR( "Changing %s display settings returned %d.\n", debugstr_us(devname), ret );
1765 return ret;
1768 /***********************************************************************
1769 * NtUserEnumDisplaySettings (win32u.@)
1771 BOOL WINAPI NtUserEnumDisplaySettings( UNICODE_STRING *device, DWORD mode,
1772 DEVMODEW *dev_mode, DWORD flags )
1774 WCHAR device_name[CCHDEVICENAME];
1775 struct adapter *adapter;
1776 BOOL ret;
1778 TRACE( "%s %#x %p %#x\n", debugstr_us(device), mode, dev_mode, flags );
1780 if (!lock_display_devices()) return FALSE;
1781 if ((adapter = find_adapter( device ))) lstrcpyW( device_name, adapter->dev.device_name );
1782 unlock_display_devices();
1783 if (!adapter)
1785 WARN( "Invalid device name %s.\n", debugstr_us(device) );
1786 return FALSE;
1789 ret = user_driver->pEnumDisplaySettingsEx( device_name, mode, dev_mode, flags );
1790 if (ret)
1791 TRACE( "device:%s mode index:%#x position:(%d,%d) resolution:%ux%u frequency:%uHz "
1792 "depth:%ubits orientation:%#x.\n", debugstr_w(device_name), mode,
1793 dev_mode->dmPosition.x, dev_mode->dmPosition.y, dev_mode->dmPelsWidth,
1794 dev_mode->dmPelsHeight, dev_mode->dmDisplayFrequency, dev_mode->dmBitsPerPel,
1795 dev_mode->dmDisplayOrientation );
1796 else
1797 WARN( "Failed to query %s display settings.\n", wine_dbgstr_w(device_name) );
1798 return ret;
1801 struct monitor_enum_info
1803 HANDLE handle;
1804 RECT rect;
1807 static unsigned int active_monitor_count(void)
1809 struct monitor *monitor;
1810 unsigned int count = 0;
1812 LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry)
1814 if ((monitor->dev.state_flags & DISPLAY_DEVICE_ACTIVE)) count++;
1816 return count;
1819 /***********************************************************************
1820 * NtUserEnumDisplayMonitors (win32u.@)
1822 BOOL WINAPI NtUserEnumDisplayMonitors( HDC hdc, RECT *rect, MONITORENUMPROC proc, LPARAM lparam )
1824 struct monitor_enum_info enum_buf[8], *enum_info = enum_buf;
1825 struct enum_display_monitor_params params;
1826 struct monitor *monitor;
1827 unsigned int count = 0, i;
1828 POINT origin;
1829 RECT limit;
1830 BOOL ret = TRUE;
1832 if (hdc)
1834 DC *dc;
1835 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
1836 origin.x = dc->attr->vis_rect.left;
1837 origin.y = dc->attr->vis_rect.top;
1838 release_dc_ptr( dc );
1839 if (NtGdiGetAppClipBox( hdc, &limit ) == ERROR) return FALSE;
1841 else
1843 origin.x = origin.y = 0;
1844 limit.left = limit.top = INT_MIN;
1845 limit.right = limit.bottom = INT_MAX;
1847 if (rect && !intersect_rect( &limit, &limit, rect )) return TRUE;
1849 if (!lock_display_devices()) return FALSE;
1851 count = list_count( &monitors );
1852 if (!count || (count > ARRAYSIZE(enum_buf) &&
1853 !(enum_info = malloc( count * sizeof(*enum_info) ))))
1855 unlock_display_devices();
1856 return FALSE;
1859 count = 0;
1860 LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry)
1862 RECT monrect;
1864 if (!(monitor->dev.state_flags & DISPLAY_DEVICE_ACTIVE)) continue;
1866 monrect = map_dpi_rect( monitor->rc_monitor, get_monitor_dpi( monitor->handle ),
1867 get_thread_dpi() );
1868 offset_rect( &monrect, -origin.x, -origin.y );
1869 if (!intersect_rect( &monrect, &monrect, &limit )) continue;
1871 enum_info[count].handle = monitor->handle;
1872 enum_info[count].rect = monrect;
1873 count++;
1876 unlock_display_devices();
1878 params.proc = proc;
1879 params.hdc = hdc;
1880 params.lparam = lparam;
1881 for (i = 0; i < count; i++)
1883 params.monitor = enum_info[i].handle;
1884 params.rect = enum_info[i].rect;
1885 if (!user32_call( NtUserCallEnumDisplayMonitor, &params, sizeof(params) ))
1887 ret = FALSE;
1888 break;
1891 if (enum_info != enum_buf) free( enum_info );
1892 return ret;
1895 static BOOL get_monitor_info( HMONITOR handle, MONITORINFO *info )
1897 struct monitor *monitor;
1898 UINT dpi_from, dpi_to;
1900 if (info->cbSize != sizeof(MONITORINFOEXW) && info->cbSize != sizeof(MONITORINFO)) return FALSE;
1902 if (!lock_display_devices()) return FALSE;
1904 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
1906 if (monitor->handle != handle) continue;
1907 if (!(monitor->dev.state_flags & DISPLAY_DEVICE_ACTIVE)) break;
1909 /* FIXME: map dpi */
1910 info->rcMonitor = monitor->rc_monitor;
1911 info->rcWork = monitor->rc_work;
1912 info->dwFlags = monitor->flags;
1913 if (info->cbSize >= sizeof(MONITORINFOEXW))
1915 if (monitor->adapter)
1916 lstrcpyW( ((MONITORINFOEXW *)info)->szDevice, monitor->adapter->dev.device_name );
1917 else
1918 asciiz_to_unicode( ((MONITORINFOEXW *)info)->szDevice, "WinDisc" );
1920 unlock_display_devices();
1922 if ((dpi_to = get_thread_dpi()))
1924 dpi_from = get_monitor_dpi( handle );
1925 info->rcMonitor = map_dpi_rect( info->rcMonitor, dpi_from, dpi_to );
1926 info->rcWork = map_dpi_rect( info->rcWork, dpi_from, dpi_to );
1928 TRACE( "flags %04x, monitor %s, work %s\n", info->dwFlags,
1929 wine_dbgstr_rect(&info->rcMonitor), wine_dbgstr_rect(&info->rcWork));
1930 return TRUE;
1933 unlock_display_devices();
1934 WARN( "invalid handle %p\n", handle );
1935 SetLastError( ERROR_INVALID_MONITOR_HANDLE );
1936 return FALSE;
1939 /***********************************************************************
1940 * NtUserGetSystemDpiForProcess (win32u.@)
1942 ULONG WINAPI NtUserGetSystemDpiForProcess( HANDLE process )
1944 if (process && process != GetCurrentProcess())
1946 FIXME( "not supported on other process %p\n", process );
1947 return 0;
1950 return system_dpi;
1953 /***********************************************************************
1954 * NtUserGetDpiForMonitor (win32u.@)
1956 BOOL WINAPI NtUserGetDpiForMonitor( HMONITOR monitor, UINT type, UINT *x, UINT *y )
1958 if (type > 2)
1960 SetLastError( ERROR_BAD_ARGUMENTS );
1961 return FALSE;
1963 if (!x || !y)
1965 SetLastError( ERROR_INVALID_ADDRESS );
1966 return FALSE;
1968 switch (get_thread_dpi_awareness())
1970 case DPI_AWARENESS_UNAWARE: *x = *y = USER_DEFAULT_SCREEN_DPI; break;
1971 case DPI_AWARENESS_SYSTEM_AWARE: *x = *y = system_dpi; break;
1972 default: *x = *y = get_monitor_dpi( monitor ); break;
1974 return TRUE;
1977 /* retrieve the cached base keys for a given entry */
1978 static BOOL get_base_keys( enum parameter_key index, HKEY *base_key, HKEY *volatile_key )
1980 static HKEY base_keys[NB_PARAM_KEYS];
1981 static HKEY volatile_keys[NB_PARAM_KEYS];
1982 WCHAR bufferW[128];
1983 HKEY key;
1985 if (!base_keys[index] && base_key)
1987 if (!(key = reg_create_key( hkcu_key, bufferW,
1988 asciiz_to_unicode( bufferW, parameter_key_names[index] ) - sizeof(WCHAR),
1989 0, NULL )))
1990 return FALSE;
1991 if (InterlockedCompareExchangePointer( (void **)&base_keys[index], key, 0 ))
1992 NtClose( key );
1994 if (!volatile_keys[index] && volatile_key)
1996 if (!(key = reg_create_key( volatile_base_key, bufferW,
1997 asciiz_to_unicode( bufferW, parameter_key_names[index] ) - sizeof(WCHAR),
1998 REG_OPTION_VOLATILE, NULL )))
1999 return FALSE;
2000 if (InterlockedCompareExchangePointer( (void **)&volatile_keys[index], key, 0 ))
2001 NtClose( key );
2003 if (base_key) *base_key = base_keys[index];
2004 if (volatile_key) *volatile_key = volatile_keys[index];
2005 return TRUE;
2008 /* load a value to a registry entry */
2009 static DWORD load_entry( struct sysparam_entry *entry, void *data, DWORD size )
2011 char buffer[4096];
2012 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
2013 DWORD count;
2014 HKEY base_key, volatile_key;
2016 if (!get_base_keys( entry->base_key, &base_key, &volatile_key )) return FALSE;
2018 if (!(count = query_reg_ascii_value( volatile_key, entry->regval, value, sizeof(buffer) )))
2019 count = query_reg_ascii_value( base_key, entry->regval, value, sizeof(buffer) );
2020 if (count > size)
2022 count = size;
2023 /* make sure strings are null-terminated */
2024 if (value->Type == REG_SZ) ((WCHAR *)value->Data)[count / sizeof(WCHAR) - 1] = 0;
2026 if (count) memcpy( data, value->Data, count );
2027 entry->loaded = TRUE;
2028 return count;
2031 /* save a value to a registry entry */
2032 static BOOL save_entry( const struct sysparam_entry *entry, const void *data, DWORD size,
2033 DWORD type, UINT flags )
2035 HKEY base_key, volatile_key;
2036 WCHAR nameW[64];
2038 asciiz_to_unicode( nameW, entry->regval );
2039 if (flags & SPIF_UPDATEINIFILE)
2041 if (!get_base_keys( entry->base_key, &base_key, &volatile_key )) return FALSE;
2042 if (!set_reg_value( base_key, nameW, type, data, size )) return FALSE;
2043 reg_delete_value( volatile_key, nameW );
2045 if (entry->mirror && get_base_keys( entry->mirror_key, &base_key, NULL ))
2047 asciiz_to_unicode( nameW, entry->mirror );
2048 set_reg_value( base_key, nameW, type, data, size );
2051 else
2053 if (!get_base_keys( entry->base_key, NULL, &volatile_key )) return FALSE;
2054 if (!set_reg_value( volatile_key, nameW, type, data, size )) return FALSE;
2056 return TRUE;
2059 /* save a string value to a registry entry */
2060 static BOOL save_entry_string( const struct sysparam_entry *entry, const WCHAR *str, UINT flags )
2062 return save_entry( entry, str, (lstrlenW(str) + 1) * sizeof(WCHAR), REG_SZ, flags );
2065 /* initialize an entry in the registry if missing */
2066 static BOOL init_entry( struct sysparam_entry *entry, const void *data, DWORD size, DWORD type )
2068 KEY_VALUE_PARTIAL_INFORMATION value;
2069 UNICODE_STRING name;
2070 WCHAR nameW[64];
2071 HKEY base_key;
2072 DWORD count;
2073 NTSTATUS status;
2075 if (!get_base_keys( entry->base_key, &base_key, NULL )) return FALSE;
2077 name.Buffer = nameW;
2078 name.MaximumLength = asciiz_to_unicode( nameW, entry->regval );
2079 name.Length = name.MaximumLength - sizeof(WCHAR);
2080 status = NtQueryValueKey( base_key, &name, KeyValuePartialInformation,
2081 &value, sizeof(value), &count );
2082 if (!status || status == STATUS_BUFFER_OVERFLOW) return TRUE;
2084 if (!set_reg_value( base_key, nameW, type, data, size )) return FALSE;
2085 if (entry->mirror && get_base_keys( entry->mirror_key, &base_key, NULL ))
2087 asciiz_to_unicode( nameW, entry->mirror );
2088 set_reg_value( base_key, nameW, type, data, size );
2090 entry->loaded = TRUE;
2091 return TRUE;
2094 /* initialize a string value in the registry if missing */
2095 static BOOL init_entry_string( struct sysparam_entry *entry, const WCHAR *str )
2097 return init_entry( entry, str, (lstrlenW(str) + 1) * sizeof(WCHAR), REG_SZ );
2100 /* set an int parameter in the registry */
2101 static BOOL set_int_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2103 WCHAR bufW[32];
2104 char buf[32];
2106 sprintf( buf, "%d", int_param );
2107 asciiz_to_unicode( bufW, buf );
2108 if (!save_entry_string( &entry->hdr, bufW, flags )) return FALSE;
2109 entry->uint.val = int_param;
2110 entry->hdr.loaded = TRUE;
2111 return TRUE;
2114 /* initialize an int parameter */
2115 static BOOL init_int_entry( union sysparam_all_entry *entry )
2117 WCHAR bufW[32];
2118 char buf[32];
2120 sprintf( buf, "%d", entry->uint.val );
2121 asciiz_to_unicode( bufW, buf );
2122 return init_entry_string( &entry->hdr, bufW );
2125 /* load a uint parameter from the registry */
2126 static BOOL get_uint_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2128 if (!ptr_param) return FALSE;
2130 if (!entry->hdr.loaded)
2132 WCHAR buf[32];
2133 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->uint.val = wcstol( buf, NULL, 10 );
2135 *(UINT *)ptr_param = entry->uint.val;
2136 return TRUE;
2139 /* set a uint parameter in the registry */
2140 static BOOL set_uint_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2142 WCHAR bufW[32];
2143 char buf[32];
2145 sprintf( buf, "%u", int_param );
2146 asciiz_to_unicode( bufW, buf );
2147 if (!save_entry_string( &entry->hdr, bufW, flags )) return FALSE;
2148 entry->uint.val = int_param;
2149 entry->hdr.loaded = TRUE;
2150 return TRUE;
2153 /* initialize a uint parameter */
2154 static BOOL init_uint_entry( union sysparam_all_entry *entry )
2156 WCHAR bufW[32];
2157 char buf[32];
2159 sprintf( buf, "%u", entry->uint.val );
2160 asciiz_to_unicode( bufW, buf );
2161 return init_entry_string( &entry->hdr, bufW );
2164 /* load a twips parameter from the registry */
2165 static BOOL get_twips_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2167 int val;
2169 if (!ptr_param) return FALSE;
2171 if (!entry->hdr.loaded)
2173 WCHAR buf[32];
2174 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->uint.val = wcstol( buf, NULL, 10 );
2177 /* Dimensions are quoted as being "twips" values if negative and pixels if positive.
2178 * One inch is 1440 twips.
2179 * See for example
2180 * Technical Reference to the Windows 2000 Registry ->
2181 * HKEY_CURRENT_USER -> Control Panel -> Desktop -> WindowMetrics
2183 val = entry->uint.val;
2184 if (val < 0)
2185 val = muldiv( -val, dpi, 1440 );
2186 else
2187 val = map_to_dpi( val, dpi );
2189 *(int *)ptr_param = val;
2190 return TRUE;
2193 /* set a twips parameter in the registry */
2194 static BOOL set_twips_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2196 int val = int_param;
2197 if (val > 0) val = map_from_system_dpi( val );
2198 return set_int_entry( entry, val, ptr_param, flags );
2201 /* load a bool parameter from the registry */
2202 static BOOL get_bool_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2204 if (!ptr_param) return FALSE;
2206 if (!entry->hdr.loaded)
2208 WCHAR buf[32];
2209 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->bool.val = wcstol( buf, NULL, 10 ) != 0;
2211 *(UINT *)ptr_param = entry->bool.val;
2212 return TRUE;
2215 /* set a bool parameter in the registry */
2216 static BOOL set_bool_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2218 WCHAR buf[] = { int_param ? '1' : '0', 0 };
2220 if (!save_entry_string( &entry->hdr, buf, flags )) return FALSE;
2221 entry->bool.val = int_param != 0;
2222 entry->hdr.loaded = TRUE;
2223 return TRUE;
2226 /* initialize a bool parameter */
2227 static BOOL init_bool_entry( union sysparam_all_entry *entry )
2229 WCHAR buf[] = { entry->bool.val ? '1' : '0', 0 };
2231 return init_entry_string( &entry->hdr, buf );
2234 /* load a bool parameter using Yes/No strings from the registry */
2235 static BOOL get_yesno_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2237 if (!ptr_param) return FALSE;
2239 if (!entry->hdr.loaded)
2241 WCHAR buf[32];
2242 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->bool.val = !wcsicmp( yesW, buf );
2244 *(UINT *)ptr_param = entry->bool.val;
2245 return TRUE;
2248 /* set a bool parameter using Yes/No strings from the registry */
2249 static BOOL set_yesno_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2251 const WCHAR *str = int_param ? yesW : noW;
2253 if (!save_entry_string( &entry->hdr, str, flags )) return FALSE;
2254 entry->bool.val = int_param != 0;
2255 entry->hdr.loaded = TRUE;
2256 return TRUE;
2259 /* initialize a bool parameter using Yes/No strings */
2260 static BOOL init_yesno_entry( union sysparam_all_entry *entry )
2262 return init_entry_string( &entry->hdr, entry->bool.val ? yesW : noW );
2265 /* load a dword (binary) parameter from the registry */
2266 static BOOL get_dword_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2268 if (!ptr_param) return FALSE;
2270 if (!entry->hdr.loaded)
2272 DWORD val;
2273 if (load_entry( &entry->hdr, &val, sizeof(val) ) == sizeof(DWORD)) entry->dword.val = val;
2275 *(DWORD *)ptr_param = entry->dword.val;
2276 return TRUE;
2279 /* set a dword (binary) parameter in the registry */
2280 static BOOL set_dword_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2282 DWORD val = PtrToUlong( ptr_param );
2284 if (!save_entry( &entry->hdr, &val, sizeof(val), REG_DWORD, flags )) return FALSE;
2285 entry->dword.val = val;
2286 entry->hdr.loaded = TRUE;
2287 return TRUE;
2290 /* initialize a dword parameter */
2291 static BOOL init_dword_entry( union sysparam_all_entry *entry )
2293 return init_entry( &entry->hdr, &entry->dword.val, sizeof(entry->dword.val), REG_DWORD );
2296 /* load an RGB parameter from the registry */
2297 static BOOL get_rgb_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2299 if (!ptr_param) return FALSE;
2301 if (!entry->hdr.loaded)
2303 WCHAR buf[32];
2305 if (load_entry( &entry->hdr, buf, sizeof(buf) ))
2307 DWORD r, g, b;
2308 WCHAR *end, *str = buf;
2310 r = wcstoul( str, &end, 10 );
2311 if (end == str || !*end) goto done;
2312 str = end + 1;
2313 g = wcstoul( str, &end, 10 );
2314 if (end == str || !*end) goto done;
2315 str = end + 1;
2316 b = wcstoul( str, &end, 10 );
2317 if (end == str) goto done;
2318 if (r > 255 || g > 255 || b > 255) goto done;
2319 entry->rgb.val = RGB( r, g, b );
2322 done:
2323 *(COLORREF *)ptr_param = entry->rgb.val;
2324 return TRUE;
2327 /* set an RGB parameter in the registry */
2328 static BOOL set_rgb_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2330 WCHAR bufW[32];
2331 char buf[32];
2332 HBRUSH brush;
2333 HPEN pen;
2335 sprintf( buf, "%u %u %u", GetRValue(int_param), GetGValue(int_param), GetBValue(int_param) );
2336 asciiz_to_unicode( bufW, buf );
2337 if (!save_entry_string( &entry->hdr, bufW, flags )) return FALSE;
2338 entry->rgb.val = int_param;
2339 entry->hdr.loaded = TRUE;
2340 if ((brush = InterlockedExchangePointer( (void **)&entry->rgb.brush, 0 )))
2342 make_gdi_object_system( brush, FALSE );
2343 NtGdiDeleteObjectApp( brush );
2345 if ((pen = InterlockedExchangePointer( (void **)&entry->rgb.pen, 0 )))
2347 make_gdi_object_system( pen, FALSE );
2348 NtGdiDeleteObjectApp( pen );
2350 return TRUE;
2353 /* initialize an RGB parameter */
2354 static BOOL init_rgb_entry( union sysparam_all_entry *entry )
2356 WCHAR bufW[32];
2357 char buf[32];
2359 sprintf( buf, "%u %u %u", GetRValue(entry->rgb.val), GetGValue(entry->rgb.val),
2360 GetBValue(entry->rgb.val) );
2361 asciiz_to_unicode( bufW, buf );
2362 return init_entry_string( &entry->hdr, bufW );
2365 /* get a path parameter in the registry */
2366 static BOOL get_path_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2368 if (!ptr_param) return FALSE;
2370 if (!entry->hdr.loaded)
2372 WCHAR buffer[MAX_PATH];
2374 if (load_entry( &entry->hdr, buffer, sizeof(buffer) ))
2375 lstrcpynW( entry->path.path, buffer, MAX_PATH );
2377 lstrcpynW( ptr_param, entry->path.path, int_param );
2378 return TRUE;
2381 /* set a path parameter in the registry */
2382 static BOOL set_path_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2384 WCHAR buffer[MAX_PATH];
2385 BOOL ret;
2387 lstrcpynW( buffer, ptr_param, MAX_PATH );
2388 ret = save_entry_string( &entry->hdr, buffer, flags );
2389 if (ret)
2391 lstrcpyW( entry->path.path, buffer );
2392 entry->hdr.loaded = TRUE;
2394 return ret;
2397 /* initialize a path parameter */
2398 static BOOL init_path_entry( union sysparam_all_entry *entry )
2400 return init_entry_string( &entry->hdr, entry->path.path );
2403 /* get a binary parameter in the registry */
2404 static BOOL get_binary_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2406 if (!ptr_param) return FALSE;
2408 if (!entry->hdr.loaded)
2410 void *buffer = malloc( entry->bin.size );
2411 DWORD len = load_entry( &entry->hdr, buffer, entry->bin.size );
2413 if (len)
2415 memcpy( entry->bin.ptr, buffer, entry->bin.size );
2416 memset( (char *)entry->bin.ptr + len, 0, entry->bin.size - len );
2418 free( buffer );
2420 memcpy( ptr_param, entry->bin.ptr, min( int_param, entry->bin.size ) );
2421 return TRUE;
2424 /* set a binary parameter in the registry */
2425 static BOOL set_binary_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2427 BOOL ret;
2428 void *buffer = malloc( entry->bin.size );
2430 memcpy( buffer, entry->bin.ptr, entry->bin.size );
2431 memcpy( buffer, ptr_param, min( int_param, entry->bin.size ));
2432 ret = save_entry( &entry->hdr, buffer, entry->bin.size, REG_BINARY, flags );
2433 if (ret)
2435 memcpy( entry->bin.ptr, buffer, entry->bin.size );
2436 entry->hdr.loaded = TRUE;
2438 free( buffer );
2439 return ret;
2442 /* initialize a binary parameter */
2443 static BOOL init_binary_entry( union sysparam_all_entry *entry )
2445 return init_entry( &entry->hdr, entry->bin.ptr, entry->bin.size, REG_BINARY );
2448 static void logfont16to32( const LOGFONT16 *font16, LPLOGFONTW font32 )
2450 font32->lfHeight = font16->lfHeight;
2451 font32->lfWidth = font16->lfWidth;
2452 font32->lfEscapement = font16->lfEscapement;
2453 font32->lfOrientation = font16->lfOrientation;
2454 font32->lfWeight = font16->lfWeight;
2455 font32->lfItalic = font16->lfItalic;
2456 font32->lfUnderline = font16->lfUnderline;
2457 font32->lfStrikeOut = font16->lfStrikeOut;
2458 font32->lfCharSet = font16->lfCharSet;
2459 font32->lfOutPrecision = font16->lfOutPrecision;
2460 font32->lfClipPrecision = font16->lfClipPrecision;
2461 font32->lfQuality = font16->lfQuality;
2462 font32->lfPitchAndFamily = font16->lfPitchAndFamily;
2463 win32u_mbtowc( NULL, font32->lfFaceName, LF_FACESIZE, font16->lfFaceName,
2464 strlen( font16->lfFaceName ));
2465 font32->lfFaceName[LF_FACESIZE-1] = 0;
2468 static void get_real_fontname( LOGFONTW *lf, WCHAR fullname[LF_FACESIZE] )
2470 struct font_enum_entry enum_entry;
2471 ULONG count = sizeof(enum_entry);
2472 HDC hdc;
2474 hdc = get_display_dc();
2475 NtGdiEnumFonts( hdc, 0, 0, lstrlenW( lf->lfFaceName ), lf->lfFaceName, lf->lfCharSet,
2476 &count, &enum_entry );
2477 release_display_dc( hdc );
2479 if (count)
2480 lstrcpyW( fullname, enum_entry.lf.elfFullName );
2481 else
2482 lstrcpyW( fullname, lf->lfFaceName );
2485 /* get text metrics and/or "average" char width of the specified logfont
2486 * for the specified dc */
2487 static void get_text_metr_size( HDC hdc, LOGFONTW *plf, TEXTMETRICW * ptm, UINT *psz)
2489 ENUMLOGFONTEXDVW exdv = { .elfEnumLogfontEx.elfLogFont = *plf };
2490 HFONT hfont, hfontsav;
2491 TEXTMETRICW tm;
2492 if (!ptm) ptm = &tm;
2493 hfont = NtGdiHfontCreate( &exdv, sizeof(exdv), 0, 0, NULL );
2494 if (!hfont || !(hfontsav = NtGdiSelectFont( hdc, hfont )))
2496 ptm->tmHeight = -1;
2497 if (psz) *psz = 10;
2498 if (hfont) NtGdiDeleteObjectApp( hfont );
2499 return;
2501 NtGdiGetTextMetricsW( hdc, ptm, 0 );
2502 if (psz)
2504 SIZE sz;
2505 static const WCHAR abcdW[] =
2506 {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
2507 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
2508 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
2509 if (NtGdiGetTextExtentExW( hdc, abcdW, ARRAYSIZE(abcdW), 0, NULL, NULL, &sz, 0 ))
2510 *psz = (sz.cx / 26 + 1) / 2;
2511 else *psz = 10;
2513 NtGdiSelectFont( hdc, hfontsav );
2514 NtGdiDeleteObjectApp( hfont );
2517 /* adjust some of the raw values found in the registry */
2518 static void normalize_nonclientmetrics( NONCLIENTMETRICSW *pncm)
2520 TEXTMETRICW tm;
2521 HDC hdc = get_display_dc();
2523 if( pncm->iBorderWidth < 1) pncm->iBorderWidth = 1;
2524 if( pncm->iCaptionWidth < 8) pncm->iCaptionWidth = 8;
2525 if( pncm->iScrollWidth < 8) pncm->iScrollWidth = 8;
2526 if( pncm->iScrollHeight < 8) pncm->iScrollHeight = 8;
2528 /* adjust some heights to the corresponding font */
2529 get_text_metr_size( hdc, &pncm->lfMenuFont, &tm, NULL);
2530 pncm->iMenuHeight = max( pncm->iMenuHeight, 2 + tm.tmHeight + tm.tmExternalLeading );
2531 get_text_metr_size( hdc, &pncm->lfCaptionFont, &tm, NULL);
2532 pncm->iCaptionHeight = max( pncm->iCaptionHeight, 2 + tm.tmHeight);
2533 get_text_metr_size( hdc, &pncm->lfSmCaptionFont, &tm, NULL);
2534 pncm->iSmCaptionHeight = max( pncm->iSmCaptionHeight, 2 + tm.tmHeight);
2535 release_display_dc( hdc );
2538 /* load a font (binary) parameter from the registry */
2539 static BOOL get_font_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2541 LOGFONTW font;
2543 if (!ptr_param) return FALSE;
2545 if (!entry->hdr.loaded)
2547 switch (load_entry( &entry->hdr, &font, sizeof(font) ))
2549 case sizeof(font):
2550 if (font.lfHeight > 0) /* positive height value means points ( inch/72 ) */
2551 font.lfHeight = -muldiv( font.lfHeight, USER_DEFAULT_SCREEN_DPI, 72 );
2552 entry->font.val = font;
2553 break;
2554 case sizeof(LOGFONT16): /* win9x-winME format */
2555 logfont16to32( (LOGFONT16 *)&font, &entry->font.val );
2556 if (entry->font.val.lfHeight > 0)
2557 entry->font.val.lfHeight = -muldiv( entry->font.val.lfHeight, USER_DEFAULT_SCREEN_DPI, 72 );
2558 break;
2559 default:
2560 WARN( "Unknown format in key %s value %s\n",
2561 debugstr_a( parameter_key_names[entry->hdr.base_key] ),
2562 debugstr_a( entry->hdr.regval ));
2563 /* fall through */
2564 case 0: /* use the default GUI font */
2565 NtGdiExtGetObjectW( get_stock_object( DEFAULT_GUI_FONT ), sizeof(font), &font );
2566 font.lfHeight = map_from_system_dpi( font.lfHeight );
2567 font.lfWeight = entry->font.weight;
2568 entry->font.val = font;
2569 break;
2571 get_real_fontname( &entry->font.val, entry->font.fullname );
2572 entry->hdr.loaded = TRUE;
2574 font = entry->font.val;
2575 font.lfHeight = map_to_dpi( font.lfHeight, dpi );
2576 lstrcpyW( font.lfFaceName, entry->font.fullname );
2577 *(LOGFONTW *)ptr_param = font;
2578 return TRUE;
2581 /* set a font (binary) parameter in the registry */
2582 static BOOL set_font_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2584 LOGFONTW font;
2585 WCHAR *ptr;
2587 memcpy( &font, ptr_param, sizeof(font) );
2588 /* zero pad the end of lfFaceName so we don't save uninitialised data */
2589 for (ptr = font.lfFaceName; ptr < font.lfFaceName + LF_FACESIZE && *ptr; ptr++);
2590 if (ptr < font.lfFaceName + LF_FACESIZE)
2591 memset( ptr, 0, (font.lfFaceName + LF_FACESIZE - ptr) * sizeof(WCHAR) );
2592 if (font.lfHeight < 0) font.lfHeight = map_from_system_dpi( font.lfHeight );
2594 if (!save_entry( &entry->hdr, &font, sizeof(font), REG_BINARY, flags )) return FALSE;
2595 entry->font.val = font;
2596 get_real_fontname( &entry->font.val, entry->font.fullname );
2597 entry->hdr.loaded = TRUE;
2598 return TRUE;
2601 /* initialize a font (binary) parameter */
2602 static BOOL init_font_entry( union sysparam_all_entry *entry )
2604 NtGdiExtGetObjectW( get_stock_object( DEFAULT_GUI_FONT ), sizeof(entry->font.val), &entry->font.val );
2605 entry->font.val.lfHeight = map_from_system_dpi( entry->font.val.lfHeight );
2606 entry->font.val.lfWeight = entry->font.weight;
2607 get_real_fontname( &entry->font.val, entry->font.fullname );
2608 return init_entry( &entry->hdr, &entry->font.val, sizeof(entry->font.val), REG_BINARY );
2611 /* get a user pref parameter in the registry */
2612 static BOOL get_userpref_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2614 union sysparam_all_entry *parent_entry = (union sysparam_all_entry *)entry->pref.parent;
2615 BYTE prefs[8];
2617 if (!ptr_param) return FALSE;
2619 if (!parent_entry->hdr.get( parent_entry, sizeof(prefs), prefs, dpi )) return FALSE;
2620 *(BOOL *)ptr_param = (prefs[entry->pref.offset] & entry->pref.mask) != 0;
2621 return TRUE;
2624 /* set a user pref parameter in the registry */
2625 static BOOL set_userpref_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2627 union sysparam_all_entry *parent_entry = (union sysparam_all_entry *)entry->pref.parent;
2628 BYTE prefs[8];
2630 parent_entry->hdr.loaded = FALSE; /* force loading it again */
2631 if (!parent_entry->hdr.get( parent_entry, sizeof(prefs), prefs, get_system_dpi() )) return FALSE;
2633 if (PtrToUlong( ptr_param )) prefs[entry->pref.offset] |= entry->pref.mask;
2634 else prefs[entry->pref.offset] &= ~entry->pref.mask;
2636 return parent_entry->hdr.set( parent_entry, sizeof(prefs), prefs, flags );
2639 static BOOL get_entry_dpi( void *ptr, UINT int_param, void *ptr_param, UINT dpi )
2641 union sysparam_all_entry *entry = ptr;
2642 return entry->hdr.get( entry, int_param, ptr_param, dpi );
2645 static BOOL get_entry( void *ptr, UINT int_param, void *ptr_param )
2647 return get_entry_dpi( ptr, int_param, ptr_param, get_system_dpi() );
2650 static BOOL set_entry( void *ptr, UINT int_param, void *ptr_param, UINT flags )
2652 union sysparam_all_entry *entry = ptr;
2653 return entry->hdr.set( entry, int_param, ptr_param, flags );
2656 #define UINT_ENTRY(name,val,base,reg) \
2657 struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_uint_entry, init_uint_entry, \
2658 base, reg }, (val) }
2660 #define UINT_ENTRY_MIRROR(name,val,base,reg,mirror_base) \
2661 struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_uint_entry, init_uint_entry, \
2662 base, reg, mirror_base, reg }, (val) }
2664 #define INT_ENTRY(name,val,base,reg) \
2665 struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_int_entry, init_int_entry, \
2666 base, reg }, (val) }
2668 #define BOOL_ENTRY(name,val,base,reg) \
2669 struct sysparam_bool_entry entry_##name = { { get_bool_entry, set_bool_entry, init_bool_entry, \
2670 base, reg }, (val) }
2672 #define BOOL_ENTRY_MIRROR(name,val,base,reg,mirror_base) \
2673 struct sysparam_bool_entry entry_##name = { { get_bool_entry, set_bool_entry, init_bool_entry, \
2674 base, reg, mirror_base, reg }, (val) }
2676 #define TWIPS_ENTRY(name,val,base,reg) \
2677 struct sysparam_uint_entry entry_##name = { { get_twips_entry, set_twips_entry, init_int_entry, \
2678 base, reg }, (val) }
2680 #define YESNO_ENTRY(name,val,base,reg) \
2681 struct sysparam_bool_entry entry_##name = { { get_yesno_entry, set_yesno_entry, init_yesno_entry, \
2682 base, reg }, (val) }
2684 #define DWORD_ENTRY(name,val,base,reg) \
2685 struct sysparam_dword_entry entry_##name = { { get_dword_entry, set_dword_entry, init_dword_entry, \
2686 base, reg }, (val) }
2688 #define BINARY_ENTRY(name,data,base,reg) \
2689 struct sysparam_binary_entry entry_##name = { { get_binary_entry, set_binary_entry, init_binary_entry, \
2690 base, reg }, data, sizeof(data) }
2692 #define PATH_ENTRY(name,base,reg) \
2693 struct sysparam_path_entry entry_##name = { { get_path_entry, set_path_entry, init_path_entry, \
2694 base, reg } }
2696 #define FONT_ENTRY(name,weight,base,reg) \
2697 struct sysparam_font_entry entry_##name = { { get_font_entry, set_font_entry, init_font_entry, \
2698 base, reg }, (weight) }
2700 #define USERPREF_ENTRY(name,offset,mask) \
2701 struct sysparam_pref_entry entry_##name = { { get_userpref_entry, set_userpref_entry }, \
2702 &entry_USERPREFERENCESMASK, (offset), (mask) }
2704 static UINT_ENTRY( DRAGWIDTH, 4, DESKTOP_KEY, "DragWidth" );
2705 static UINT_ENTRY( DRAGHEIGHT, 4, DESKTOP_KEY, "DragHeight" );
2706 static UINT_ENTRY( DOUBLECLICKTIME, 500, MOUSE_KEY, "DoubleClickSpeed" );
2707 static UINT_ENTRY( FONTSMOOTHING, 2, DESKTOP_KEY, "FontSmoothing" );
2708 static UINT_ENTRY( GRIDGRANULARITY, 0, DESKTOP_KEY, "GridGranularity" );
2709 static UINT_ENTRY( KEYBOARDDELAY, 1, KEYBOARD_KEY, "KeyboardDelay" );
2710 static UINT_ENTRY( KEYBOARDSPEED, 31, KEYBOARD_KEY, "KeyboardSpeed" );
2711 static UINT_ENTRY( MENUSHOWDELAY, 400, DESKTOP_KEY, "MenuShowDelay" );
2712 static UINT_ENTRY( MINARRANGE, ARW_HIDE, METRICS_KEY, "MinArrange" );
2713 static UINT_ENTRY( MINHORZGAP, 0, METRICS_KEY, "MinHorzGap" );
2714 static UINT_ENTRY( MINVERTGAP, 0, METRICS_KEY, "MinVertGap" );
2715 static UINT_ENTRY( MINWIDTH, 154, METRICS_KEY, "MinWidth" );
2716 static UINT_ENTRY( MOUSEHOVERHEIGHT, 4, MOUSE_KEY, "MouseHoverHeight" );
2717 static UINT_ENTRY( MOUSEHOVERTIME, 400, MOUSE_KEY, "MouseHoverTime" );
2718 static UINT_ENTRY( MOUSEHOVERWIDTH, 4, MOUSE_KEY, "MouseHoverWidth" );
2719 static UINT_ENTRY( MOUSESPEED, 10, MOUSE_KEY, "MouseSensitivity" );
2720 static UINT_ENTRY( MOUSETRAILS, 0, MOUSE_KEY, "MouseTrails" );
2721 static UINT_ENTRY( SCREENSAVETIMEOUT, 300, DESKTOP_KEY, "ScreenSaveTimeOut" );
2722 static UINT_ENTRY( WHEELSCROLLCHARS, 3, DESKTOP_KEY, "WheelScrollChars" );
2723 static UINT_ENTRY( WHEELSCROLLLINES, 3, DESKTOP_KEY, "WheelScrollLines" );
2724 static UINT_ENTRY_MIRROR( DOUBLECLKHEIGHT, 4, MOUSE_KEY, "DoubleClickHeight", DESKTOP_KEY );
2725 static UINT_ENTRY_MIRROR( DOUBLECLKWIDTH, 4, MOUSE_KEY, "DoubleClickWidth", DESKTOP_KEY );
2726 static UINT_ENTRY_MIRROR( MENUDROPALIGNMENT, 0, DESKTOP_KEY, "MenuDropAlignment", VERSION_KEY );
2728 static INT_ENTRY( MOUSETHRESHOLD1, 6, MOUSE_KEY, "MouseThreshold1" );
2729 static INT_ENTRY( MOUSETHRESHOLD2, 10, MOUSE_KEY, "MouseThreshold2" );
2730 static INT_ENTRY( MOUSEACCELERATION, 1, MOUSE_KEY, "MouseSpeed" );
2732 static BOOL_ENTRY( BLOCKSENDINPUTRESETS, FALSE, DESKTOP_KEY, "BlockSendInputResets" );
2733 static BOOL_ENTRY( DRAGFULLWINDOWS, FALSE, DESKTOP_KEY, "DragFullWindows" );
2734 static BOOL_ENTRY( KEYBOARDPREF, TRUE, KEYBOARDPREF_KEY, "On" );
2735 static BOOL_ENTRY( LOWPOWERACTIVE, FALSE, DESKTOP_KEY, "LowPowerActive" );
2736 static BOOL_ENTRY( MOUSEBUTTONSWAP, FALSE, MOUSE_KEY, "SwapMouseButtons" );
2737 static BOOL_ENTRY( POWEROFFACTIVE, FALSE, DESKTOP_KEY, "PowerOffActive" );
2738 static BOOL_ENTRY( SCREENREADER, FALSE, SCREENREADER_KEY, "On" );
2739 static BOOL_ENTRY( SCREENSAVEACTIVE, TRUE, DESKTOP_KEY, "ScreenSaveActive" );
2740 static BOOL_ENTRY( SCREENSAVERRUNNING, FALSE, DESKTOP_KEY, "WINE_ScreenSaverRunning" ); /* FIXME - real value */
2741 static BOOL_ENTRY( SHOWSOUNDS, FALSE, SHOWSOUNDS_KEY, "On" );
2742 static BOOL_ENTRY( SNAPTODEFBUTTON, FALSE, MOUSE_KEY, "SnapToDefaultButton" );
2743 static BOOL_ENTRY_MIRROR( ICONTITLEWRAP, TRUE, DESKTOP_KEY, "IconTitleWrap", METRICS_KEY );
2744 static BOOL_ENTRY( AUDIODESC_ON, FALSE, AUDIODESC_KEY, "On" );
2746 static TWIPS_ENTRY( BORDER, -15, METRICS_KEY, "BorderWidth" );
2747 static TWIPS_ENTRY( CAPTIONHEIGHT, -270, METRICS_KEY, "CaptionHeight" );
2748 static TWIPS_ENTRY( CAPTIONWIDTH, -270, METRICS_KEY, "CaptionWidth" );
2749 static TWIPS_ENTRY( ICONHORIZONTALSPACING, -1125, METRICS_KEY, "IconSpacing" );
2750 static TWIPS_ENTRY( ICONVERTICALSPACING, -1125, METRICS_KEY, "IconVerticalSpacing" );
2751 static TWIPS_ENTRY( MENUHEIGHT, -270, METRICS_KEY, "MenuHeight" );
2752 static TWIPS_ENTRY( MENUWIDTH, -270, METRICS_KEY, "MenuWidth" );
2753 static TWIPS_ENTRY( PADDEDBORDERWIDTH, 0, METRICS_KEY, "PaddedBorderWidth" );
2754 static TWIPS_ENTRY( SCROLLHEIGHT, -240, METRICS_KEY, "ScrollHeight" );
2755 static TWIPS_ENTRY( SCROLLWIDTH, -240, METRICS_KEY, "ScrollWidth" );
2756 static TWIPS_ENTRY( SMCAPTIONHEIGHT, -225, METRICS_KEY, "SmCaptionHeight" );
2757 static TWIPS_ENTRY( SMCAPTIONWIDTH, -225, METRICS_KEY, "SmCaptionWidth" );
2759 static YESNO_ENTRY( BEEP, TRUE, SOUND_KEY, "Beep" );
2761 static DWORD_ENTRY( ACTIVEWINDOWTRACKING, 0, MOUSE_KEY, "ActiveWindowTracking" );
2762 static DWORD_ENTRY( ACTIVEWNDTRKTIMEOUT, 0, DESKTOP_KEY, "ActiveWndTrackTimeout" );
2763 static DWORD_ENTRY( CARETWIDTH, 1, DESKTOP_KEY, "CaretWidth" );
2764 static DWORD_ENTRY( DPISCALINGVER, 0, DESKTOP_KEY, "DpiScalingVer" );
2765 static DWORD_ENTRY( FOCUSBORDERHEIGHT, 1, DESKTOP_KEY, "FocusBorderHeight" );
2766 static DWORD_ENTRY( FOCUSBORDERWIDTH, 1, DESKTOP_KEY, "FocusBorderWidth" );
2767 static DWORD_ENTRY( FONTSMOOTHINGCONTRAST, 0, DESKTOP_KEY, "FontSmoothingGamma" );
2768 static DWORD_ENTRY( FONTSMOOTHINGORIENTATION, FE_FONTSMOOTHINGORIENTATIONRGB, DESKTOP_KEY, "FontSmoothingOrientation" );
2769 static DWORD_ENTRY( FONTSMOOTHINGTYPE, FE_FONTSMOOTHINGSTANDARD, DESKTOP_KEY, "FontSmoothingType" );
2770 static DWORD_ENTRY( FOREGROUNDFLASHCOUNT, 3, DESKTOP_KEY, "ForegroundFlashCount" );
2771 static DWORD_ENTRY( FOREGROUNDLOCKTIMEOUT, 0, DESKTOP_KEY, "ForegroundLockTimeout" );
2772 static DWORD_ENTRY( LOGPIXELS, 0, DESKTOP_KEY, "LogPixels" );
2773 static DWORD_ENTRY( MOUSECLICKLOCKTIME, 1200, DESKTOP_KEY, "ClickLockTime" );
2774 static DWORD_ENTRY( AUDIODESC_LOCALE, 0, AUDIODESC_KEY, "Locale" );
2776 static PATH_ENTRY( DESKPATTERN, DESKTOP_KEY, "Pattern" );
2777 static PATH_ENTRY( DESKWALLPAPER, DESKTOP_KEY, "Wallpaper" );
2779 static BYTE user_prefs[8] = { 0x30, 0x00, 0x00, 0x80, 0x12, 0x00, 0x00, 0x00 };
2780 static BINARY_ENTRY( USERPREFERENCESMASK, user_prefs, DESKTOP_KEY, "UserPreferencesMask" );
2782 static FONT_ENTRY( CAPTIONLOGFONT, FW_BOLD, METRICS_KEY, "CaptionFont" );
2783 static FONT_ENTRY( ICONTITLELOGFONT, FW_NORMAL, METRICS_KEY, "IconFont" );
2784 static FONT_ENTRY( MENULOGFONT, FW_NORMAL, METRICS_KEY, "MenuFont" );
2785 static FONT_ENTRY( MESSAGELOGFONT, FW_NORMAL, METRICS_KEY, "MessageFont" );
2786 static FONT_ENTRY( SMCAPTIONLOGFONT, FW_NORMAL, METRICS_KEY, "SmCaptionFont" );
2787 static FONT_ENTRY( STATUSLOGFONT, FW_NORMAL, METRICS_KEY, "StatusFont" );
2789 static USERPREF_ENTRY( MENUANIMATION, 0, 0x02 );
2790 static USERPREF_ENTRY( COMBOBOXANIMATION, 0, 0x04 );
2791 static USERPREF_ENTRY( LISTBOXSMOOTHSCROLLING, 0, 0x08 );
2792 static USERPREF_ENTRY( GRADIENTCAPTIONS, 0, 0x10 );
2793 static USERPREF_ENTRY( KEYBOARDCUES, 0, 0x20 );
2794 static USERPREF_ENTRY( ACTIVEWNDTRKZORDER, 0, 0x40 );
2795 static USERPREF_ENTRY( HOTTRACKING, 0, 0x80 );
2796 static USERPREF_ENTRY( MENUFADE, 1, 0x02 );
2797 static USERPREF_ENTRY( SELECTIONFADE, 1, 0x04 );
2798 static USERPREF_ENTRY( TOOLTIPANIMATION, 1, 0x08 );
2799 static USERPREF_ENTRY( TOOLTIPFADE, 1, 0x10 );
2800 static USERPREF_ENTRY( CURSORSHADOW, 1, 0x20 );
2801 static USERPREF_ENTRY( MOUSESONAR, 1, 0x40 );
2802 static USERPREF_ENTRY( MOUSECLICKLOCK, 1, 0x80 );
2803 static USERPREF_ENTRY( MOUSEVANISH, 2, 0x01 );
2804 static USERPREF_ENTRY( FLATMENU, 2, 0x02 );
2805 static USERPREF_ENTRY( DROPSHADOW, 2, 0x04 );
2806 static USERPREF_ENTRY( UIEFFECTS, 3, 0x80 );
2807 static USERPREF_ENTRY( DISABLEOVERLAPPEDCONTENT, 4, 0x01 );
2808 static USERPREF_ENTRY( CLIENTAREAANIMATION, 4, 0x02 );
2809 static USERPREF_ENTRY( CLEARTYPE, 4, 0x10 );
2810 static USERPREF_ENTRY( SPEECHRECOGNITION, 4, 0x20 );
2812 /* System parameter indexes */
2813 enum spi_index
2815 SPI_SETWORKAREA_IDX,
2816 SPI_INDEX_COUNT
2819 /* indicators whether system parameter value is loaded */
2820 static char spi_loaded[SPI_INDEX_COUNT];
2822 static struct sysparam_rgb_entry system_colors[] =
2824 #define RGB_ENTRY(name,val,reg) { { get_rgb_entry, set_rgb_entry, init_rgb_entry, COLORS_KEY, reg }, (val) }
2825 RGB_ENTRY( COLOR_SCROLLBAR, RGB(212, 208, 200), "Scrollbar" ),
2826 RGB_ENTRY( COLOR_BACKGROUND, RGB(58, 110, 165), "Background" ),
2827 RGB_ENTRY( COLOR_ACTIVECAPTION, RGB(10, 36, 106), "ActiveTitle" ),
2828 RGB_ENTRY( COLOR_INACTIVECAPTION, RGB(128, 128, 128), "InactiveTitle" ),
2829 RGB_ENTRY( COLOR_MENU, RGB(212, 208, 200), "Menu" ),
2830 RGB_ENTRY( COLOR_WINDOW, RGB(255, 255, 255), "Window" ),
2831 RGB_ENTRY( COLOR_WINDOWFRAME, RGB(0, 0, 0), "WindowFrame" ),
2832 RGB_ENTRY( COLOR_MENUTEXT, RGB(0, 0, 0), "MenuText" ),
2833 RGB_ENTRY( COLOR_WINDOWTEXT, RGB(0, 0, 0), "WindowText" ),
2834 RGB_ENTRY( COLOR_CAPTIONTEXT, RGB(255, 255, 255), "TitleText" ),
2835 RGB_ENTRY( COLOR_ACTIVEBORDER, RGB(212, 208, 200), "ActiveBorder" ),
2836 RGB_ENTRY( COLOR_INACTIVEBORDER, RGB(212, 208, 200), "InactiveBorder" ),
2837 RGB_ENTRY( COLOR_APPWORKSPACE, RGB(128, 128, 128), "AppWorkSpace" ),
2838 RGB_ENTRY( COLOR_HIGHLIGHT, RGB(10, 36, 106), "Hilight" ),
2839 RGB_ENTRY( COLOR_HIGHLIGHTTEXT, RGB(255, 255, 255), "HilightText" ),
2840 RGB_ENTRY( COLOR_BTNFACE, RGB(212, 208, 200), "ButtonFace" ),
2841 RGB_ENTRY( COLOR_BTNSHADOW, RGB(128, 128, 128), "ButtonShadow" ),
2842 RGB_ENTRY( COLOR_GRAYTEXT, RGB(128, 128, 128), "GrayText" ),
2843 RGB_ENTRY( COLOR_BTNTEXT, RGB(0, 0, 0), "ButtonText" ),
2844 RGB_ENTRY( COLOR_INACTIVECAPTIONTEXT, RGB(212, 208, 200), "InactiveTitleText" ),
2845 RGB_ENTRY( COLOR_BTNHIGHLIGHT, RGB(255, 255, 255), "ButtonHilight" ),
2846 RGB_ENTRY( COLOR_3DDKSHADOW, RGB(64, 64, 64), "ButtonDkShadow" ),
2847 RGB_ENTRY( COLOR_3DLIGHT, RGB(212, 208, 200), "ButtonLight" ),
2848 RGB_ENTRY( COLOR_INFOTEXT, RGB(0, 0, 0), "InfoText" ),
2849 RGB_ENTRY( COLOR_INFOBK, RGB(255, 255, 225), "InfoWindow" ),
2850 RGB_ENTRY( COLOR_ALTERNATEBTNFACE, RGB(181, 181, 181), "ButtonAlternateFace" ),
2851 RGB_ENTRY( COLOR_HOTLIGHT, RGB(0, 0, 200), "HotTrackingColor" ),
2852 RGB_ENTRY( COLOR_GRADIENTACTIVECAPTION, RGB(166, 202, 240), "GradientActiveTitle" ),
2853 RGB_ENTRY( COLOR_GRADIENTINACTIVECAPTION, RGB(192, 192, 192), "GradientInactiveTitle" ),
2854 RGB_ENTRY( COLOR_MENUHILIGHT, RGB(10, 36, 106), "MenuHilight" ),
2855 RGB_ENTRY( COLOR_MENUBAR, RGB(212, 208, 200), "MenuBar" )
2856 #undef RGB_ENTRY
2859 /* entries that are initialized by default in the registry */
2860 static union sysparam_all_entry * const default_entries[] =
2862 (union sysparam_all_entry *)&entry_ACTIVEWINDOWTRACKING,
2863 (union sysparam_all_entry *)&entry_ACTIVEWNDTRKTIMEOUT,
2864 (union sysparam_all_entry *)&entry_BEEP,
2865 (union sysparam_all_entry *)&entry_BLOCKSENDINPUTRESETS,
2866 (union sysparam_all_entry *)&entry_BORDER,
2867 (union sysparam_all_entry *)&entry_CAPTIONHEIGHT,
2868 (union sysparam_all_entry *)&entry_CAPTIONWIDTH,
2869 (union sysparam_all_entry *)&entry_CARETWIDTH,
2870 (union sysparam_all_entry *)&entry_DESKWALLPAPER,
2871 (union sysparam_all_entry *)&entry_DOUBLECLICKTIME,
2872 (union sysparam_all_entry *)&entry_DOUBLECLKHEIGHT,
2873 (union sysparam_all_entry *)&entry_DOUBLECLKWIDTH,
2874 (union sysparam_all_entry *)&entry_DRAGFULLWINDOWS,
2875 (union sysparam_all_entry *)&entry_DRAGHEIGHT,
2876 (union sysparam_all_entry *)&entry_DRAGWIDTH,
2877 (union sysparam_all_entry *)&entry_FOCUSBORDERHEIGHT,
2878 (union sysparam_all_entry *)&entry_FOCUSBORDERWIDTH,
2879 (union sysparam_all_entry *)&entry_FONTSMOOTHING,
2880 (union sysparam_all_entry *)&entry_FONTSMOOTHINGCONTRAST,
2881 (union sysparam_all_entry *)&entry_FONTSMOOTHINGORIENTATION,
2882 (union sysparam_all_entry *)&entry_FONTSMOOTHINGTYPE,
2883 (union sysparam_all_entry *)&entry_FOREGROUNDFLASHCOUNT,
2884 (union sysparam_all_entry *)&entry_FOREGROUNDLOCKTIMEOUT,
2885 (union sysparam_all_entry *)&entry_ICONHORIZONTALSPACING,
2886 (union sysparam_all_entry *)&entry_ICONTITLEWRAP,
2887 (union sysparam_all_entry *)&entry_ICONVERTICALSPACING,
2888 (union sysparam_all_entry *)&entry_KEYBOARDDELAY,
2889 (union sysparam_all_entry *)&entry_KEYBOARDPREF,
2890 (union sysparam_all_entry *)&entry_KEYBOARDSPEED,
2891 (union sysparam_all_entry *)&entry_LOWPOWERACTIVE,
2892 (union sysparam_all_entry *)&entry_MENUHEIGHT,
2893 (union sysparam_all_entry *)&entry_MENUSHOWDELAY,
2894 (union sysparam_all_entry *)&entry_MENUWIDTH,
2895 (union sysparam_all_entry *)&entry_MOUSEACCELERATION,
2896 (union sysparam_all_entry *)&entry_MOUSEBUTTONSWAP,
2897 (union sysparam_all_entry *)&entry_MOUSECLICKLOCKTIME,
2898 (union sysparam_all_entry *)&entry_MOUSEHOVERHEIGHT,
2899 (union sysparam_all_entry *)&entry_MOUSEHOVERTIME,
2900 (union sysparam_all_entry *)&entry_MOUSEHOVERWIDTH,
2901 (union sysparam_all_entry *)&entry_MOUSESPEED,
2902 (union sysparam_all_entry *)&entry_MOUSETHRESHOLD1,
2903 (union sysparam_all_entry *)&entry_MOUSETHRESHOLD2,
2904 (union sysparam_all_entry *)&entry_PADDEDBORDERWIDTH,
2905 (union sysparam_all_entry *)&entry_SCREENREADER,
2906 (union sysparam_all_entry *)&entry_SCROLLHEIGHT,
2907 (union sysparam_all_entry *)&entry_SCROLLWIDTH,
2908 (union sysparam_all_entry *)&entry_SHOWSOUNDS,
2909 (union sysparam_all_entry *)&entry_SMCAPTIONHEIGHT,
2910 (union sysparam_all_entry *)&entry_SMCAPTIONWIDTH,
2911 (union sysparam_all_entry *)&entry_SNAPTODEFBUTTON,
2912 (union sysparam_all_entry *)&entry_USERPREFERENCESMASK,
2913 (union sysparam_all_entry *)&entry_WHEELSCROLLCHARS,
2914 (union sysparam_all_entry *)&entry_WHEELSCROLLLINES,
2915 (union sysparam_all_entry *)&entry_AUDIODESC_LOCALE,
2916 (union sysparam_all_entry *)&entry_AUDIODESC_ON,
2919 void sysparams_init(void)
2922 DWORD i, dispos, dpi_scaling;
2923 WCHAR layout[KL_NAMELENGTH];
2924 HKEY hkey;
2926 static const WCHAR software_wineW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e'};
2927 static const WCHAR temporary_system_parametersW[] =
2928 {'T','e','m','p','o','r','a','r','y',' ','S','y','s','t','e','m',' ',
2929 'P','a','r','a','m','e','t','e','r','s'};
2930 static const WCHAR oneW[] = {'1',0};
2931 static const WCHAR kl_preloadW[] =
2932 {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d'};
2934 if ((hkey = reg_create_key( hkcu_key, kl_preloadW, sizeof(kl_preloadW), 0, NULL )))
2936 if (NtUserGetKeyboardLayoutName( layout ))
2937 set_reg_value( hkey, oneW, REG_SZ, (const BYTE *)layout,
2938 (lstrlenW(layout) + 1) * sizeof(WCHAR) );
2939 NtClose( hkey );
2942 /* this one must be non-volatile */
2943 if (!(hkey = reg_create_key( hkcu_key, software_wineW, sizeof(software_wineW), 0, NULL )))
2945 ERR("Can't create wine registry branch\n");
2946 return;
2949 /* @@ Wine registry key: HKCU\Software\Wine\Temporary System Parameters */
2950 if (!(volatile_base_key = reg_create_key( hkey, temporary_system_parametersW,
2951 sizeof(temporary_system_parametersW),
2952 REG_OPTION_VOLATILE, &dispos )))
2953 ERR("Can't create non-permanent wine registry branch\n");
2955 NtClose( hkey );
2957 config_key = reg_create_key( NULL, config_keyW, sizeof(config_keyW), 0, NULL );
2959 get_dword_entry( (union sysparam_all_entry *)&entry_LOGPIXELS, 0, &system_dpi, 0 );
2960 if (!system_dpi) /* check fallback key */
2962 static const WCHAR log_pixelsW[] = {'L','o','g','P','i','x','e','l','s',0};
2963 static const WCHAR software_fontsW[] =
2964 {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s'};
2966 if ((hkey = reg_open_key( config_key, software_fontsW, sizeof(software_fontsW) )))
2968 char buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD)];
2969 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
2971 if (query_reg_value( hkey, log_pixelsW, value, sizeof(buffer) ) && value->Type == REG_DWORD)
2972 system_dpi = *(const DWORD *)value->Data;
2973 NtClose( hkey );
2976 if (!system_dpi) system_dpi = USER_DEFAULT_SCREEN_DPI;
2978 /* FIXME: what do the DpiScalingVer flags mean? */
2979 get_dword_entry( (union sysparam_all_entry *)&entry_DPISCALINGVER, 0, &dpi_scaling, 0 );
2980 if (!dpi_scaling) NtUserSetProcessDpiAwarenessContext( NTUSER_DPI_PER_MONITOR_AWARE, 0 );
2982 if (volatile_base_key && dispos == REG_CREATED_NEW_KEY) /* first process, initialize entries */
2984 for (i = 0; i < ARRAY_SIZE( default_entries ); i++)
2985 default_entries[i]->hdr.init( default_entries[i] );
2989 static BOOL update_desktop_wallpaper(void)
2991 /* FIXME: move implementation from user32 */
2992 entry_DESKWALLPAPER.hdr.loaded = entry_DESKPATTERN.hdr.loaded = FALSE;
2993 return TRUE;
2996 /***********************************************************************
2997 * NtUserSystemParametersInfoForDpi (win32u.@)
2999 BOOL WINAPI NtUserSystemParametersInfoForDpi( UINT action, UINT val, PVOID ptr, UINT winini, UINT dpi )
3001 BOOL ret = FALSE;
3003 switch (action)
3005 case SPI_GETICONTITLELOGFONT:
3006 ret = get_entry_dpi( &entry_ICONTITLELOGFONT, val, ptr, dpi );
3007 break;
3008 case SPI_GETNONCLIENTMETRICS:
3010 NONCLIENTMETRICSW *ncm = ptr;
3012 if (!ncm) break;
3013 ret = get_entry_dpi( &entry_BORDER, 0, &ncm->iBorderWidth, dpi ) &&
3014 get_entry_dpi( &entry_SCROLLWIDTH, 0, &ncm->iScrollWidth, dpi ) &&
3015 get_entry_dpi( &entry_SCROLLHEIGHT, 0, &ncm->iScrollHeight, dpi ) &&
3016 get_entry_dpi( &entry_CAPTIONWIDTH, 0, &ncm->iCaptionWidth, dpi ) &&
3017 get_entry_dpi( &entry_CAPTIONHEIGHT, 0, &ncm->iCaptionHeight, dpi ) &&
3018 get_entry_dpi( &entry_CAPTIONLOGFONT, 0, &ncm->lfCaptionFont, dpi ) &&
3019 get_entry_dpi( &entry_SMCAPTIONWIDTH, 0, &ncm->iSmCaptionWidth, dpi ) &&
3020 get_entry_dpi( &entry_SMCAPTIONHEIGHT, 0, &ncm->iSmCaptionHeight, dpi ) &&
3021 get_entry_dpi( &entry_SMCAPTIONLOGFONT, 0, &ncm->lfSmCaptionFont, dpi ) &&
3022 get_entry_dpi( &entry_MENUWIDTH, 0, &ncm->iMenuWidth, dpi ) &&
3023 get_entry_dpi( &entry_MENUHEIGHT, 0, &ncm->iMenuHeight, dpi ) &&
3024 get_entry_dpi( &entry_MENULOGFONT, 0, &ncm->lfMenuFont, dpi ) &&
3025 get_entry_dpi( &entry_STATUSLOGFONT, 0, &ncm->lfStatusFont, dpi ) &&
3026 get_entry_dpi( &entry_MESSAGELOGFONT, 0, &ncm->lfMessageFont, dpi );
3027 if (ret && ncm->cbSize == sizeof(NONCLIENTMETRICSW))
3028 ret = get_entry_dpi( &entry_PADDEDBORDERWIDTH, 0, &ncm->iPaddedBorderWidth, dpi );
3029 normalize_nonclientmetrics( ncm );
3030 break;
3032 case SPI_GETICONMETRICS:
3034 ICONMETRICSW *im = ptr;
3035 if (im && im->cbSize == sizeof(*im))
3036 ret = get_entry_dpi( &entry_ICONHORIZONTALSPACING, 0, &im->iHorzSpacing, dpi ) &&
3037 get_entry_dpi( &entry_ICONVERTICALSPACING, 0, &im->iVertSpacing, dpi ) &&
3038 get_entry_dpi( &entry_ICONTITLEWRAP, 0, &im->iTitleWrap, dpi ) &&
3039 get_entry_dpi( &entry_ICONTITLELOGFONT, 0, &im->lfFont, dpi );
3040 break;
3042 default:
3043 SetLastError( ERROR_INVALID_PARAMETER );
3044 break;
3046 return ret;
3049 /***********************************************************************
3050 * NtUserSystemParametersInfo (win32u.@)
3052 * Each system parameter has flag which shows whether the parameter
3053 * is loaded or not. Parameters, stored directly in SysParametersInfo are
3054 * loaded from registry only when they are requested and the flag is
3055 * "false", after the loading the flag is set to "true". On interprocess
3056 * notification of the parameter change the corresponding parameter flag is
3057 * set to "false". The parameter value will be reloaded when it is requested
3058 * the next time.
3059 * Parameters, backed by or depend on GetSystemMetrics are processed
3060 * differently. These parameters are always loaded. They are reloaded right
3061 * away on interprocess change notification. We can't do lazy loading because
3062 * we don't want to complicate GetSystemMetrics.
3063 * Parameters backed by driver settings are read from corresponding setting.
3064 * On the parameter change request the setting is changed. Interprocess change
3065 * notifications are ignored.
3066 * When parameter value is updated the changed value is stored in permanent
3067 * registry branch if saving is requested. Otherwise it is stored
3068 * in temporary branch
3070 * Some SPI values can also be stored as Twips values in the registry,
3071 * don't forget the conversion!
3073 BOOL WINAPI NtUserSystemParametersInfo( UINT action, UINT val, void *ptr, UINT winini )
3075 #define WINE_SPI_FIXME(x) \
3076 case x: \
3078 static BOOL warn = TRUE; \
3079 if (warn) \
3081 warn = FALSE; \
3082 FIXME( "Unimplemented action: %u (%s)\n", x, #x ); \
3085 SetLastError( ERROR_INVALID_SPI_VALUE ); \
3086 ret = FALSE; \
3087 break
3088 #define WINE_SPI_WARN(x) \
3089 case x: \
3090 WARN( "Ignored action: %u (%s)\n", x, #x ); \
3091 ret = TRUE; \
3092 break
3094 BOOL ret = user_driver->pSystemParametersInfo( action, val, ptr, winini );
3095 unsigned spi_idx = 0;
3097 if (!ret) switch (action)
3099 case SPI_GETBEEP:
3100 ret = get_entry( &entry_BEEP, val, ptr );
3101 break;
3102 case SPI_SETBEEP:
3103 ret = set_entry( &entry_BEEP, val, ptr, winini );
3104 break;
3105 case SPI_GETMOUSE:
3106 ret = get_entry( &entry_MOUSETHRESHOLD1, val, (INT *)ptr ) &&
3107 get_entry( &entry_MOUSETHRESHOLD2, val, (INT *)ptr + 1 ) &&
3108 get_entry( &entry_MOUSEACCELERATION, val, (INT *)ptr + 2 );
3109 break;
3110 case SPI_SETMOUSE:
3111 ret = set_entry( &entry_MOUSETHRESHOLD1, ((INT *)ptr)[0], ptr, winini ) &&
3112 set_entry( &entry_MOUSETHRESHOLD2, ((INT *)ptr)[1], ptr, winini ) &&
3113 set_entry( &entry_MOUSEACCELERATION, ((INT *)ptr)[2], ptr, winini );
3114 break;
3115 case SPI_GETBORDER:
3116 ret = get_entry( &entry_BORDER, val, ptr );
3117 if (*(INT*)ptr < 1) *(INT*)ptr = 1;
3118 break;
3119 case SPI_SETBORDER:
3120 ret = set_entry( &entry_BORDER, val, ptr, winini );
3121 break;
3122 case SPI_GETKEYBOARDSPEED:
3123 ret = get_entry( &entry_KEYBOARDSPEED, val, ptr );
3124 break;
3125 case SPI_SETKEYBOARDSPEED:
3126 if (val > 31) val = 31;
3127 ret = set_entry( &entry_KEYBOARDSPEED, val, ptr, winini );
3128 break;
3130 WINE_SPI_WARN(SPI_LANGDRIVER); /* not implemented in Windows */
3132 case SPI_ICONHORIZONTALSPACING:
3133 if (ptr != NULL)
3134 ret = get_entry( &entry_ICONHORIZONTALSPACING, val, ptr );
3135 else
3137 int min_val = map_to_dpi( 32, get_system_dpi() );
3138 ret = set_entry( &entry_ICONHORIZONTALSPACING, max( min_val, val ), ptr, winini );
3140 break;
3141 case SPI_GETSCREENSAVETIMEOUT:
3142 ret = get_entry( &entry_SCREENSAVETIMEOUT, val, ptr );
3143 break;
3144 case SPI_SETSCREENSAVETIMEOUT:
3145 ret = set_entry( &entry_SCREENSAVETIMEOUT, val, ptr, winini );
3146 break;
3147 case SPI_GETSCREENSAVEACTIVE:
3148 ret = get_entry( &entry_SCREENSAVEACTIVE, val, ptr );
3149 break;
3150 case SPI_SETSCREENSAVEACTIVE:
3151 ret = set_entry( &entry_SCREENSAVEACTIVE, val, ptr, winini );
3152 break;
3153 case SPI_GETGRIDGRANULARITY:
3154 ret = get_entry( &entry_GRIDGRANULARITY, val, ptr );
3155 break;
3156 case SPI_SETGRIDGRANULARITY:
3157 ret = set_entry( &entry_GRIDGRANULARITY, val, ptr, winini );
3158 break;
3159 case SPI_SETDESKWALLPAPER:
3160 if (!ptr || set_entry( &entry_DESKWALLPAPER, val, ptr, winini ))
3161 ret = update_desktop_wallpaper();
3162 break;
3163 case SPI_SETDESKPATTERN:
3164 if (!ptr || set_entry( &entry_DESKPATTERN, val, ptr, winini ))
3165 ret = update_desktop_wallpaper();
3166 break;
3167 case SPI_GETKEYBOARDDELAY:
3168 ret = get_entry( &entry_KEYBOARDDELAY, val, ptr );
3169 break;
3170 case SPI_SETKEYBOARDDELAY:
3171 ret = set_entry( &entry_KEYBOARDDELAY, val, ptr, winini );
3172 break;
3173 case SPI_ICONVERTICALSPACING:
3174 if (ptr != NULL)
3175 ret = get_entry( &entry_ICONVERTICALSPACING, val, ptr );
3176 else
3178 int min_val = map_to_dpi( 32, get_system_dpi() );
3179 ret = set_entry( &entry_ICONVERTICALSPACING, max( min_val, val ), ptr, winini );
3181 break;
3182 case SPI_GETICONTITLEWRAP:
3183 ret = get_entry( &entry_ICONTITLEWRAP, val, ptr );
3184 break;
3185 case SPI_SETICONTITLEWRAP:
3186 ret = set_entry( &entry_ICONTITLEWRAP, val, ptr, winini );
3187 break;
3188 case SPI_GETMENUDROPALIGNMENT:
3189 ret = get_entry( &entry_MENUDROPALIGNMENT, val, ptr );
3190 break;
3191 case SPI_SETMENUDROPALIGNMENT:
3192 ret = set_entry( &entry_MENUDROPALIGNMENT, val, ptr, winini );
3193 break;
3194 case SPI_SETDOUBLECLKWIDTH:
3195 ret = set_entry( &entry_DOUBLECLKWIDTH, val, ptr, winini );
3196 break;
3197 case SPI_SETDOUBLECLKHEIGHT:
3198 ret = set_entry( &entry_DOUBLECLKHEIGHT, val, ptr, winini );
3199 break;
3200 case SPI_GETICONTITLELOGFONT:
3201 ret = get_entry( &entry_ICONTITLELOGFONT, val, ptr );
3202 break;
3203 case SPI_SETDOUBLECLICKTIME:
3204 ret = set_entry( &entry_DOUBLECLICKTIME, val, ptr, winini );
3205 break;
3206 case SPI_SETMOUSEBUTTONSWAP:
3207 ret = set_entry( &entry_MOUSEBUTTONSWAP, val, ptr, winini );
3208 break;
3209 case SPI_SETICONTITLELOGFONT:
3210 ret = set_entry( &entry_ICONTITLELOGFONT, val, ptr, winini );
3211 break;
3212 case SPI_GETFASTTASKSWITCH:
3213 if (!ptr) return FALSE;
3214 *(BOOL *)ptr = TRUE;
3215 ret = TRUE;
3216 break;
3217 case SPI_SETFASTTASKSWITCH:
3218 /* the action is disabled */
3219 ret = FALSE;
3220 break;
3221 case SPI_SETDRAGFULLWINDOWS:
3222 ret = set_entry( &entry_DRAGFULLWINDOWS, val, ptr, winini );
3223 break;
3224 case SPI_GETDRAGFULLWINDOWS:
3225 ret = get_entry( &entry_DRAGFULLWINDOWS, val, ptr );
3226 break;
3227 case SPI_GETNONCLIENTMETRICS:
3229 NONCLIENTMETRICSW *nm = ptr;
3230 int padded_border;
3232 if (!ptr) return FALSE;
3234 ret = get_entry( &entry_BORDER, 0, &nm->iBorderWidth ) &&
3235 get_entry( &entry_PADDEDBORDERWIDTH, 0, &padded_border ) &&
3236 get_entry( &entry_SCROLLWIDTH, 0, &nm->iScrollWidth ) &&
3237 get_entry( &entry_SCROLLHEIGHT, 0, &nm->iScrollHeight ) &&
3238 get_entry( &entry_CAPTIONWIDTH, 0, &nm->iCaptionWidth ) &&
3239 get_entry( &entry_CAPTIONHEIGHT, 0, &nm->iCaptionHeight ) &&
3240 get_entry( &entry_CAPTIONLOGFONT, 0, &nm->lfCaptionFont ) &&
3241 get_entry( &entry_SMCAPTIONWIDTH, 0, &nm->iSmCaptionWidth ) &&
3242 get_entry( &entry_SMCAPTIONHEIGHT, 0, &nm->iSmCaptionHeight ) &&
3243 get_entry( &entry_SMCAPTIONLOGFONT, 0, &nm->lfSmCaptionFont ) &&
3244 get_entry( &entry_MENUWIDTH, 0, &nm->iMenuWidth ) &&
3245 get_entry( &entry_MENUHEIGHT, 0, &nm->iMenuHeight ) &&
3246 get_entry( &entry_MENULOGFONT, 0, &nm->lfMenuFont ) &&
3247 get_entry( &entry_STATUSLOGFONT, 0, &nm->lfStatusFont ) &&
3248 get_entry( &entry_MESSAGELOGFONT, 0, &nm->lfMessageFont );
3249 if (ret)
3251 nm->iBorderWidth += padded_border;
3252 if (nm->cbSize == sizeof(NONCLIENTMETRICSW)) nm->iPaddedBorderWidth = 0;
3254 normalize_nonclientmetrics( nm );
3255 break;
3257 case SPI_SETNONCLIENTMETRICS:
3259 LPNONCLIENTMETRICSW nm = ptr;
3260 int padded_border;
3262 if (nm && (nm->cbSize == sizeof(NONCLIENTMETRICSW) ||
3263 nm->cbSize == FIELD_OFFSET(NONCLIENTMETRICSW, iPaddedBorderWidth)))
3265 get_entry( &entry_PADDEDBORDERWIDTH, 0, &padded_border );
3267 ret = set_entry( &entry_BORDER, nm->iBorderWidth - padded_border, NULL, winini ) &&
3268 set_entry( &entry_SCROLLWIDTH, nm->iScrollWidth, NULL, winini ) &&
3269 set_entry( &entry_SCROLLHEIGHT, nm->iScrollHeight, NULL, winini ) &&
3270 set_entry( &entry_CAPTIONWIDTH, nm->iCaptionWidth, NULL, winini ) &&
3271 set_entry( &entry_CAPTIONHEIGHT, nm->iCaptionHeight, NULL, winini ) &&
3272 set_entry( &entry_SMCAPTIONWIDTH, nm->iSmCaptionWidth, NULL, winini ) &&
3273 set_entry( &entry_SMCAPTIONHEIGHT, nm->iSmCaptionHeight, NULL, winini ) &&
3274 set_entry( &entry_MENUWIDTH, nm->iMenuWidth, NULL, winini ) &&
3275 set_entry( &entry_MENUHEIGHT, nm->iMenuHeight, NULL, winini ) &&
3276 set_entry( &entry_MENULOGFONT, 0, &nm->lfMenuFont, winini ) &&
3277 set_entry( &entry_CAPTIONLOGFONT, 0, &nm->lfCaptionFont, winini ) &&
3278 set_entry( &entry_SMCAPTIONLOGFONT, 0, &nm->lfSmCaptionFont, winini ) &&
3279 set_entry( &entry_STATUSLOGFONT, 0, &nm->lfStatusFont, winini ) &&
3280 set_entry( &entry_MESSAGELOGFONT, 0, &nm->lfMessageFont, winini );
3282 break;
3284 case SPI_GETMINIMIZEDMETRICS:
3286 MINIMIZEDMETRICS *mm = ptr;
3287 if (mm && mm->cbSize == sizeof(*mm)) {
3288 ret = get_entry( &entry_MINWIDTH, 0, &mm->iWidth ) &&
3289 get_entry( &entry_MINHORZGAP, 0, &mm->iHorzGap ) &&
3290 get_entry( &entry_MINVERTGAP, 0, &mm->iVertGap ) &&
3291 get_entry( &entry_MINARRANGE, 0, &mm->iArrange );
3292 mm->iWidth = max( 0, mm->iWidth );
3293 mm->iHorzGap = max( 0, mm->iHorzGap );
3294 mm->iVertGap = max( 0, mm->iVertGap );
3295 mm->iArrange &= 0x0f;
3297 break;
3299 case SPI_SETMINIMIZEDMETRICS:
3301 MINIMIZEDMETRICS *mm = ptr;
3302 if (mm && mm->cbSize == sizeof(*mm))
3303 ret = set_entry( &entry_MINWIDTH, max( 0, mm->iWidth ), NULL, winini ) &&
3304 set_entry( &entry_MINHORZGAP, max( 0, mm->iHorzGap ), NULL, winini ) &&
3305 set_entry( &entry_MINVERTGAP, max( 0, mm->iVertGap ), NULL, winini ) &&
3306 set_entry( &entry_MINARRANGE, mm->iArrange & 0x0f, NULL, winini );
3307 break;
3309 case SPI_GETICONMETRICS:
3311 ICONMETRICSW *icon = ptr;
3312 if(icon && icon->cbSize == sizeof(*icon))
3314 ret = get_entry( &entry_ICONHORIZONTALSPACING, 0, &icon->iHorzSpacing ) &&
3315 get_entry( &entry_ICONVERTICALSPACING, 0, &icon->iVertSpacing ) &&
3316 get_entry( &entry_ICONTITLEWRAP, 0, &icon->iTitleWrap ) &&
3317 get_entry( &entry_ICONTITLELOGFONT, 0, &icon->lfFont );
3319 break;
3321 case SPI_SETICONMETRICS:
3323 ICONMETRICSW *icon = ptr;
3324 if (icon && icon->cbSize == sizeof(*icon))
3325 ret = set_entry( &entry_ICONVERTICALSPACING, max(32,icon->iVertSpacing), NULL, winini ) &&
3326 set_entry( &entry_ICONHORIZONTALSPACING, max(32,icon->iHorzSpacing), NULL, winini ) &&
3327 set_entry( &entry_ICONTITLEWRAP, icon->iTitleWrap, NULL, winini ) &&
3328 set_entry( &entry_ICONTITLELOGFONT, 0, &icon->lfFont, winini );
3329 break;
3331 case SPI_SETWORKAREA:
3333 if (!ptr) return FALSE;
3334 spi_idx = SPI_SETWORKAREA_IDX;
3335 work_area = *(RECT*)ptr;
3336 spi_loaded[spi_idx] = TRUE;
3337 ret = TRUE;
3338 break;
3340 case SPI_GETWORKAREA:
3342 if (!ptr) return FALSE;
3344 spi_idx = SPI_SETWORKAREA_IDX;
3345 if (!spi_loaded[spi_idx])
3347 struct monitor *monitor;
3349 if (!lock_display_devices()) return FALSE;
3351 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
3353 if (!(monitor->flags & MONITORINFOF_PRIMARY)) continue;
3354 work_area = monitor->rc_work;
3355 break;
3358 unlock_display_devices();
3359 spi_loaded[spi_idx] = TRUE;
3361 *(RECT *)ptr = map_dpi_rect( work_area, system_dpi, get_thread_dpi() );
3362 ret = TRUE;
3363 TRACE("work area %s\n", wine_dbgstr_rect( &work_area ));
3364 break;
3367 WINE_SPI_FIXME(SPI_SETPENWINDOWS);
3369 case SPI_GETFILTERKEYS:
3371 LPFILTERKEYS filter_keys = ptr;
3372 WARN("SPI_GETFILTERKEYS not fully implemented\n");
3373 if (filter_keys && filter_keys->cbSize == sizeof(FILTERKEYS))
3375 /* Indicate that no FilterKeys feature available */
3376 filter_keys->dwFlags = 0;
3377 filter_keys->iWaitMSec = 0;
3378 filter_keys->iDelayMSec = 0;
3379 filter_keys->iRepeatMSec = 0;
3380 filter_keys->iBounceMSec = 0;
3381 ret = TRUE;
3383 break;
3385 WINE_SPI_FIXME(SPI_SETFILTERKEYS);
3387 case SPI_GETTOGGLEKEYS:
3389 LPTOGGLEKEYS toggle_keys = ptr;
3390 WARN("SPI_GETTOGGLEKEYS not fully implemented\n");
3391 if (toggle_keys && toggle_keys->cbSize == sizeof(TOGGLEKEYS))
3393 /* Indicate that no ToggleKeys feature available */
3394 toggle_keys->dwFlags = 0;
3395 ret = TRUE;
3397 break;
3400 WINE_SPI_FIXME(SPI_SETTOGGLEKEYS);
3402 case SPI_GETMOUSEKEYS:
3404 MOUSEKEYS *mouse_keys = ptr;
3405 WARN("SPI_GETMOUSEKEYS not fully implemented\n");
3406 if (mouse_keys && mouse_keys->cbSize == sizeof(MOUSEKEYS))
3408 /* Indicate that no MouseKeys feature available */
3409 mouse_keys->dwFlags = 0;
3410 mouse_keys->iMaxSpeed = 360;
3411 mouse_keys->iTimeToMaxSpeed = 1000;
3412 mouse_keys->iCtrlSpeed = 0;
3413 mouse_keys->dwReserved1 = 0;
3414 mouse_keys->dwReserved2 = 0;
3415 ret = TRUE;
3417 break;
3420 WINE_SPI_FIXME(SPI_SETMOUSEKEYS);
3422 case SPI_GETSHOWSOUNDS:
3423 ret = get_entry( &entry_SHOWSOUNDS, val, ptr );
3424 break;
3425 case SPI_SETSHOWSOUNDS:
3426 ret = set_entry( &entry_SHOWSOUNDS, val, ptr, winini );
3427 break;
3428 case SPI_GETSTICKYKEYS:
3430 STICKYKEYS *sticky_keys = ptr;
3431 WARN("SPI_GETSTICKYKEYS not fully implemented\n");
3432 if (sticky_keys && sticky_keys->cbSize == sizeof(STICKYKEYS))
3434 /* Indicate that no StickyKeys feature available */
3435 sticky_keys->dwFlags = 0;
3436 ret = TRUE;
3438 break;
3441 WINE_SPI_FIXME(SPI_SETSTICKYKEYS);
3443 case SPI_GETACCESSTIMEOUT:
3445 ACCESSTIMEOUT *access_timeout = ptr;
3446 WARN("SPI_GETACCESSTIMEOUT not fully implemented\n");
3447 if (access_timeout && access_timeout->cbSize == sizeof(ACCESSTIMEOUT))
3449 /* Indicate that no accessibility features timeout is available */
3450 access_timeout->dwFlags = 0;
3451 access_timeout->iTimeOutMSec = 0;
3452 ret = TRUE;
3454 break;
3457 WINE_SPI_FIXME(SPI_SETACCESSTIMEOUT);
3459 case SPI_GETSERIALKEYS:
3461 LPSERIALKEYSW serial_keys = ptr;
3462 WARN("SPI_GETSERIALKEYS not fully implemented\n");
3463 if (serial_keys && serial_keys->cbSize == sizeof(SERIALKEYSW))
3465 /* Indicate that no SerialKeys feature available */
3466 serial_keys->dwFlags = 0;
3467 serial_keys->lpszActivePort = NULL;
3468 serial_keys->lpszPort = NULL;
3469 serial_keys->iBaudRate = 0;
3470 serial_keys->iPortState = 0;
3471 ret = TRUE;
3473 break;
3476 WINE_SPI_FIXME(SPI_SETSERIALKEYS);
3478 case SPI_GETSOUNDSENTRY:
3480 SOUNDSENTRYW *sound_sentry = ptr;
3481 WARN("SPI_GETSOUNDSENTRY not fully implemented\n");
3482 if (sound_sentry && sound_sentry->cbSize == sizeof(SOUNDSENTRYW))
3484 /* Indicate that no SoundSentry feature available */
3485 sound_sentry->dwFlags = 0;
3486 sound_sentry->iFSTextEffect = 0;
3487 sound_sentry->iFSTextEffectMSec = 0;
3488 sound_sentry->iFSTextEffectColorBits = 0;
3489 sound_sentry->iFSGrafEffect = 0;
3490 sound_sentry->iFSGrafEffectMSec = 0;
3491 sound_sentry->iFSGrafEffectColor = 0;
3492 sound_sentry->iWindowsEffect = 0;
3493 sound_sentry->iWindowsEffectMSec = 0;
3494 sound_sentry->lpszWindowsEffectDLL = 0;
3495 sound_sentry->iWindowsEffectOrdinal = 0;
3496 ret = TRUE;
3498 break;
3501 WINE_SPI_FIXME(SPI_SETSOUNDSENTRY);
3503 case SPI_GETHIGHCONTRAST:
3505 HIGHCONTRASTW *high_contrast = ptr;
3506 WARN("SPI_GETHIGHCONTRAST not fully implemented\n");
3507 if (high_contrast && high_contrast->cbSize == sizeof(HIGHCONTRASTW))
3509 /* Indicate that no high contrast feature available */
3510 high_contrast->dwFlags = 0;
3511 high_contrast->lpszDefaultScheme = NULL;
3512 ret = TRUE;
3514 break;
3517 WINE_SPI_FIXME(SPI_SETHIGHCONTRAST);
3519 case SPI_GETKEYBOARDPREF:
3520 ret = get_entry( &entry_KEYBOARDPREF, val, ptr );
3521 break;
3522 case SPI_SETKEYBOARDPREF:
3523 ret = set_entry( &entry_KEYBOARDPREF, val, ptr, winini );
3524 break;
3525 case SPI_GETSCREENREADER:
3526 ret = get_entry( &entry_SCREENREADER, val, ptr );
3527 break;
3528 case SPI_SETSCREENREADER:
3529 ret = set_entry( &entry_SCREENREADER, val, ptr, winini );
3530 break;
3532 case SPI_GETANIMATION:
3534 ANIMATIONINFO *anim_info = ptr;
3536 /* Tell it "disabled" */
3537 if (anim_info && anim_info->cbSize == sizeof(ANIMATIONINFO))
3539 /* Minimize and restore animation is disabled (nonzero == enabled) */
3540 anim_info->iMinAnimate = 0;
3541 ret = TRUE;
3543 break;
3546 WINE_SPI_WARN(SPI_SETANIMATION);
3548 case SPI_GETFONTSMOOTHING:
3549 ret = get_entry( &entry_FONTSMOOTHING, val, ptr );
3550 if (ret) *(UINT *)ptr = (*(UINT *)ptr != 0);
3551 break;
3552 case SPI_SETFONTSMOOTHING:
3553 val = val ? 2 : 0; /* Win NT4/2k/XP behavior */
3554 ret = set_entry( &entry_FONTSMOOTHING, val, ptr, winini );
3555 break;
3556 case SPI_SETDRAGWIDTH:
3557 ret = set_entry( &entry_DRAGWIDTH, val, ptr, winini );
3558 break;
3559 case SPI_SETDRAGHEIGHT:
3560 ret = set_entry( &entry_DRAGHEIGHT, val, ptr, winini );
3561 break;
3563 WINE_SPI_FIXME(SPI_SETHANDHELD);
3564 WINE_SPI_FIXME(SPI_GETLOWPOWERTIMEOUT);
3565 WINE_SPI_FIXME(SPI_GETPOWEROFFTIMEOUT);
3566 WINE_SPI_FIXME(SPI_SETLOWPOWERTIMEOUT);
3567 WINE_SPI_FIXME(SPI_SETPOWEROFFTIMEOUT);
3569 case SPI_GETLOWPOWERACTIVE:
3570 ret = get_entry( &entry_LOWPOWERACTIVE, val, ptr );
3571 break;
3572 case SPI_SETLOWPOWERACTIVE:
3573 ret = set_entry( &entry_LOWPOWERACTIVE, val, ptr, winini );
3574 break;
3575 case SPI_GETPOWEROFFACTIVE:
3576 ret = get_entry( &entry_POWEROFFACTIVE, val, ptr );
3577 break;
3578 case SPI_SETPOWEROFFACTIVE:
3579 ret = set_entry( &entry_POWEROFFACTIVE, val, ptr, winini );
3580 break;
3582 WINE_SPI_FIXME(SPI_SETCURSORS);
3583 WINE_SPI_FIXME(SPI_SETICONS);
3585 case SPI_GETDEFAULTINPUTLANG:
3586 ret = NtUserGetKeyboardLayout(0) != 0;
3587 break;
3589 WINE_SPI_FIXME(SPI_SETDEFAULTINPUTLANG);
3590 WINE_SPI_FIXME(SPI_SETLANGTOGGLE);
3592 case SPI_GETWINDOWSEXTENSION:
3593 WARN( "pretend no support for Win9x Plus! for now.\n" );
3594 ret = FALSE; /* yes, this is the result value */
3595 break;
3596 case SPI_SETMOUSETRAILS:
3597 ret = set_entry( &entry_MOUSETRAILS, val, ptr, winini );
3598 break;
3599 case SPI_GETMOUSETRAILS:
3600 ret = get_entry( &entry_MOUSETRAILS, val, ptr );
3601 break;
3602 case SPI_GETSNAPTODEFBUTTON:
3603 ret = get_entry( &entry_SNAPTODEFBUTTON, val, ptr );
3604 break;
3605 case SPI_SETSNAPTODEFBUTTON:
3606 ret = set_entry( &entry_SNAPTODEFBUTTON, val, ptr, winini );
3607 break;
3608 case SPI_SETSCREENSAVERRUNNING:
3609 ret = set_entry( &entry_SCREENSAVERRUNNING, val, ptr, winini );
3610 break;
3611 case SPI_GETMOUSEHOVERWIDTH:
3612 ret = get_entry( &entry_MOUSEHOVERWIDTH, val, ptr );
3613 break;
3614 case SPI_SETMOUSEHOVERWIDTH:
3615 ret = set_entry( &entry_MOUSEHOVERWIDTH, val, ptr, winini );
3616 break;
3617 case SPI_GETMOUSEHOVERHEIGHT:
3618 ret = get_entry( &entry_MOUSEHOVERHEIGHT, val, ptr );
3619 break;
3620 case SPI_SETMOUSEHOVERHEIGHT:
3621 ret = set_entry( &entry_MOUSEHOVERHEIGHT, val, ptr, winini );
3622 break;
3623 case SPI_GETMOUSEHOVERTIME:
3624 ret = get_entry( &entry_MOUSEHOVERTIME, val, ptr );
3625 break;
3626 case SPI_SETMOUSEHOVERTIME:
3627 ret = set_entry( &entry_MOUSEHOVERTIME, val, ptr, winini );
3628 break;
3629 case SPI_GETWHEELSCROLLLINES:
3630 ret = get_entry( &entry_WHEELSCROLLLINES, val, ptr );
3631 break;
3632 case SPI_SETWHEELSCROLLLINES:
3633 ret = set_entry( &entry_WHEELSCROLLLINES, val, ptr, winini );
3634 break;
3635 case SPI_GETMENUSHOWDELAY:
3636 ret = get_entry( &entry_MENUSHOWDELAY, val, ptr );
3637 break;
3638 case SPI_SETMENUSHOWDELAY:
3639 ret = set_entry( &entry_MENUSHOWDELAY, val, ptr, winini );
3640 break;
3641 case SPI_GETWHEELSCROLLCHARS:
3642 ret = get_entry( &entry_WHEELSCROLLCHARS, val, ptr );
3643 break;
3644 case SPI_SETWHEELSCROLLCHARS:
3645 ret = set_entry( &entry_WHEELSCROLLCHARS, val, ptr, winini );
3646 break;
3648 WINE_SPI_FIXME(SPI_GETSHOWIMEUI);
3649 WINE_SPI_FIXME(SPI_SETSHOWIMEUI);
3651 case SPI_GETMOUSESPEED:
3652 ret = get_entry( &entry_MOUSESPEED, val, ptr );
3653 break;
3654 case SPI_SETMOUSESPEED:
3655 ret = set_entry( &entry_MOUSESPEED, val, ptr, winini );
3656 break;
3657 case SPI_GETSCREENSAVERRUNNING:
3658 ret = get_entry( &entry_SCREENSAVERRUNNING, val, ptr );
3659 break;
3660 case SPI_GETDESKWALLPAPER:
3661 ret = get_entry( &entry_DESKWALLPAPER, val, ptr );
3662 break;
3663 case SPI_GETACTIVEWINDOWTRACKING:
3664 ret = get_entry( &entry_ACTIVEWINDOWTRACKING, val, ptr );
3665 break;
3666 case SPI_SETACTIVEWINDOWTRACKING:
3667 ret = set_entry( &entry_ACTIVEWINDOWTRACKING, val, ptr, winini );
3668 break;
3669 case SPI_GETMENUANIMATION:
3670 ret = get_entry( &entry_MENUANIMATION, val, ptr );
3671 break;
3672 case SPI_SETMENUANIMATION:
3673 ret = set_entry( &entry_MENUANIMATION, val, ptr, winini );
3674 break;
3675 case SPI_GETCOMBOBOXANIMATION:
3676 ret = get_entry( &entry_COMBOBOXANIMATION, val, ptr );
3677 break;
3678 case SPI_SETCOMBOBOXANIMATION:
3679 ret = set_entry( &entry_COMBOBOXANIMATION, val, ptr, winini );
3680 break;
3681 case SPI_GETLISTBOXSMOOTHSCROLLING:
3682 ret = get_entry( &entry_LISTBOXSMOOTHSCROLLING, val, ptr );
3683 break;
3684 case SPI_SETLISTBOXSMOOTHSCROLLING:
3685 ret = set_entry( &entry_LISTBOXSMOOTHSCROLLING, val, ptr, winini );
3686 break;
3687 case SPI_GETGRADIENTCAPTIONS:
3688 ret = get_entry( &entry_GRADIENTCAPTIONS, val, ptr );
3689 break;
3690 case SPI_SETGRADIENTCAPTIONS:
3691 ret = set_entry( &entry_GRADIENTCAPTIONS, val, ptr, winini );
3692 break;
3693 case SPI_GETKEYBOARDCUES:
3694 ret = get_entry( &entry_KEYBOARDCUES, val, ptr );
3695 break;
3696 case SPI_SETKEYBOARDCUES:
3697 ret = set_entry( &entry_KEYBOARDCUES, val, ptr, winini );
3698 break;
3699 case SPI_GETACTIVEWNDTRKZORDER:
3700 ret = get_entry( &entry_ACTIVEWNDTRKZORDER, val, ptr );
3701 break;
3702 case SPI_SETACTIVEWNDTRKZORDER:
3703 ret = set_entry( &entry_ACTIVEWNDTRKZORDER, val, ptr, winini );
3704 break;
3705 case SPI_GETHOTTRACKING:
3706 ret = get_entry( &entry_HOTTRACKING, val, ptr );
3707 break;
3708 case SPI_SETHOTTRACKING:
3709 ret = set_entry( &entry_HOTTRACKING, val, ptr, winini );
3710 break;
3711 case SPI_GETMENUFADE:
3712 ret = get_entry( &entry_MENUFADE, val, ptr );
3713 break;
3714 case SPI_SETMENUFADE:
3715 ret = set_entry( &entry_MENUFADE, val, ptr, winini );
3716 break;
3717 case SPI_GETSELECTIONFADE:
3718 ret = get_entry( &entry_SELECTIONFADE, val, ptr );
3719 break;
3720 case SPI_SETSELECTIONFADE:
3721 ret = set_entry( &entry_SELECTIONFADE, val, ptr, winini );
3722 break;
3723 case SPI_GETTOOLTIPANIMATION:
3724 ret = get_entry( &entry_TOOLTIPANIMATION, val, ptr );
3725 break;
3726 case SPI_SETTOOLTIPANIMATION:
3727 ret = set_entry( &entry_TOOLTIPANIMATION, val, ptr, winini );
3728 break;
3729 case SPI_GETTOOLTIPFADE:
3730 ret = get_entry( &entry_TOOLTIPFADE, val, ptr );
3731 break;
3732 case SPI_SETTOOLTIPFADE:
3733 ret = set_entry( &entry_TOOLTIPFADE, val, ptr, winini );
3734 break;
3735 case SPI_GETCURSORSHADOW:
3736 ret = get_entry( &entry_CURSORSHADOW, val, ptr );
3737 break;
3738 case SPI_SETCURSORSHADOW:
3739 ret = set_entry( &entry_CURSORSHADOW, val, ptr, winini );
3740 break;
3741 case SPI_GETMOUSESONAR:
3742 ret = get_entry( &entry_MOUSESONAR, val, ptr );
3743 break;
3744 case SPI_SETMOUSESONAR:
3745 ret = set_entry( &entry_MOUSESONAR, val, ptr, winini );
3746 break;
3747 case SPI_GETMOUSECLICKLOCK:
3748 ret = get_entry( &entry_MOUSECLICKLOCK, val, ptr );
3749 break;
3750 case SPI_SETMOUSECLICKLOCK:
3751 ret = set_entry( &entry_MOUSECLICKLOCK, val, ptr, winini );
3752 break;
3753 case SPI_GETMOUSEVANISH:
3754 ret = get_entry( &entry_MOUSEVANISH, val, ptr );
3755 break;
3756 case SPI_SETMOUSEVANISH:
3757 ret = set_entry( &entry_MOUSEVANISH, val, ptr, winini );
3758 break;
3759 case SPI_GETFLATMENU:
3760 ret = get_entry( &entry_FLATMENU, val, ptr );
3761 break;
3762 case SPI_SETFLATMENU:
3763 ret = set_entry( &entry_FLATMENU, val, ptr, winini );
3764 break;
3765 case SPI_GETDROPSHADOW:
3766 ret = get_entry( &entry_DROPSHADOW, val, ptr );
3767 break;
3768 case SPI_SETDROPSHADOW:
3769 ret = set_entry( &entry_DROPSHADOW, val, ptr, winini );
3770 break;
3771 case SPI_GETBLOCKSENDINPUTRESETS:
3772 ret = get_entry( &entry_BLOCKSENDINPUTRESETS, val, ptr );
3773 break;
3774 case SPI_SETBLOCKSENDINPUTRESETS:
3775 ret = set_entry( &entry_BLOCKSENDINPUTRESETS, val, ptr, winini );
3776 break;
3777 case SPI_GETUIEFFECTS:
3778 ret = get_entry( &entry_UIEFFECTS, val, ptr );
3779 break;
3780 case SPI_SETUIEFFECTS:
3781 /* FIXME: this probably should mask other UI effect values when unset */
3782 ret = set_entry( &entry_UIEFFECTS, val, ptr, winini );
3783 break;
3784 case SPI_GETDISABLEOVERLAPPEDCONTENT:
3785 ret = get_entry( &entry_DISABLEOVERLAPPEDCONTENT, val, ptr );
3786 break;
3787 case SPI_SETDISABLEOVERLAPPEDCONTENT:
3788 ret = set_entry( &entry_DISABLEOVERLAPPEDCONTENT, val, ptr, winini );
3789 break;
3790 case SPI_GETCLIENTAREAANIMATION:
3791 ret = get_entry( &entry_CLIENTAREAANIMATION, val, ptr );
3792 break;
3793 case SPI_SETCLIENTAREAANIMATION:
3794 ret = set_entry( &entry_CLIENTAREAANIMATION, val, ptr, winini );
3795 break;
3796 case SPI_GETCLEARTYPE:
3797 ret = get_entry( &entry_CLEARTYPE, val, ptr );
3798 break;
3799 case SPI_SETCLEARTYPE:
3800 ret = set_entry( &entry_CLEARTYPE, val, ptr, winini );
3801 break;
3802 case SPI_GETSPEECHRECOGNITION:
3803 ret = get_entry( &entry_SPEECHRECOGNITION, val, ptr );
3804 break;
3805 case SPI_SETSPEECHRECOGNITION:
3806 ret = set_entry( &entry_SPEECHRECOGNITION, val, ptr, winini );
3807 break;
3808 case SPI_GETFOREGROUNDLOCKTIMEOUT:
3809 ret = get_entry( &entry_FOREGROUNDLOCKTIMEOUT, val, ptr );
3810 break;
3811 case SPI_SETFOREGROUNDLOCKTIMEOUT:
3812 /* FIXME: this should check that the calling thread
3813 * is able to change the foreground window */
3814 ret = set_entry( &entry_FOREGROUNDLOCKTIMEOUT, val, ptr, winini );
3815 break;
3816 case SPI_GETACTIVEWNDTRKTIMEOUT:
3817 ret = get_entry( &entry_ACTIVEWNDTRKTIMEOUT, val, ptr );
3818 break;
3819 case SPI_SETACTIVEWNDTRKTIMEOUT:
3820 ret = get_entry( &entry_ACTIVEWNDTRKTIMEOUT, val, ptr );
3821 break;
3822 case SPI_GETFOREGROUNDFLASHCOUNT:
3823 ret = get_entry( &entry_FOREGROUNDFLASHCOUNT, val, ptr );
3824 break;
3825 case SPI_SETFOREGROUNDFLASHCOUNT:
3826 ret = set_entry( &entry_FOREGROUNDFLASHCOUNT, val, ptr, winini );
3827 break;
3828 case SPI_GETCARETWIDTH:
3829 ret = get_entry( &entry_CARETWIDTH, val, ptr );
3830 break;
3831 case SPI_SETCARETWIDTH:
3832 ret = set_entry( &entry_CARETWIDTH, val, ptr, winini );
3833 break;
3834 case SPI_GETMOUSECLICKLOCKTIME:
3835 ret = get_entry( &entry_MOUSECLICKLOCKTIME, val, ptr );
3836 break;
3837 case SPI_SETMOUSECLICKLOCKTIME:
3838 ret = set_entry( &entry_MOUSECLICKLOCKTIME, val, ptr, winini );
3839 break;
3840 case SPI_GETFONTSMOOTHINGTYPE:
3841 ret = get_entry( &entry_FONTSMOOTHINGTYPE, val, ptr );
3842 break;
3843 case SPI_SETFONTSMOOTHINGTYPE:
3844 ret = set_entry( &entry_FONTSMOOTHINGTYPE, val, ptr, winini );
3845 break;
3846 case SPI_GETFONTSMOOTHINGCONTRAST:
3847 ret = get_entry( &entry_FONTSMOOTHINGCONTRAST, val, ptr );
3848 break;
3849 case SPI_SETFONTSMOOTHINGCONTRAST:
3850 ret = set_entry( &entry_FONTSMOOTHINGCONTRAST, val, ptr, winini );
3851 break;
3852 case SPI_GETFOCUSBORDERWIDTH:
3853 ret = get_entry( &entry_FOCUSBORDERWIDTH, val, ptr );
3854 break;
3855 case SPI_GETFOCUSBORDERHEIGHT:
3856 ret = get_entry( &entry_FOCUSBORDERHEIGHT, val, ptr );
3857 break;
3858 case SPI_SETFOCUSBORDERWIDTH:
3859 ret = set_entry( &entry_FOCUSBORDERWIDTH, val, ptr, winini );
3860 break;
3861 case SPI_SETFOCUSBORDERHEIGHT:
3862 ret = set_entry( &entry_FOCUSBORDERHEIGHT, val, ptr, winini );
3863 break;
3864 case SPI_GETFONTSMOOTHINGORIENTATION:
3865 ret = get_entry( &entry_FONTSMOOTHINGORIENTATION, val, ptr );
3866 break;
3867 case SPI_SETFONTSMOOTHINGORIENTATION:
3868 ret = set_entry( &entry_FONTSMOOTHINGORIENTATION, val, ptr, winini );
3869 break;
3870 case SPI_GETAUDIODESCRIPTION:
3872 AUDIODESCRIPTION *audio = ptr;
3873 if (audio && audio->cbSize == sizeof(AUDIODESCRIPTION) && val == sizeof(AUDIODESCRIPTION) )
3875 ret = get_entry( &entry_AUDIODESC_ON, 0, &audio->Enabled ) &&
3876 get_entry( &entry_AUDIODESC_LOCALE, 0, &audio->Locale );
3878 break;
3880 case SPI_SETAUDIODESCRIPTION:
3882 AUDIODESCRIPTION *audio = ptr;
3883 if (audio && audio->cbSize == sizeof(AUDIODESCRIPTION) && val == sizeof(AUDIODESCRIPTION) )
3885 ret = set_entry( &entry_AUDIODESC_ON, 0, &audio->Enabled, winini) &&
3886 set_entry( &entry_AUDIODESC_LOCALE, 0, &audio->Locale, winini );
3888 break;
3890 default:
3891 FIXME( "Unknown action: %u\n", action );
3892 SetLastError( ERROR_INVALID_SPI_VALUE );
3893 ret = FALSE;
3894 break;
3897 if (ret && (winini & SPIF_UPDATEINIFILE))
3899 static const WCHAR emptyW[1];
3900 if (winini & (SPIF_SENDWININICHANGE | SPIF_SENDCHANGE))
3901 user_callbacks->pSendMessageTimeoutW( HWND_BROADCAST, WM_SETTINGCHANGE,
3902 action, (LPARAM) emptyW,
3903 SMTO_ABORTIFHUNG, 2000, NULL );
3905 TRACE( "(%u, %u, %p, %u) ret %d\n", action, val, ptr, winini, ret );
3906 return ret;
3908 #undef WINE_SPI_FIXME
3909 #undef WINE_SPI_WARN
3912 int get_system_metrics( int index )
3914 NONCLIENTMETRICSW ncm;
3915 MINIMIZEDMETRICS mm;
3916 ICONMETRICSW im;
3917 RECT rect;
3918 UINT ret;
3919 HDC hdc;
3921 /* some metrics are dynamic */
3922 switch (index)
3924 case SM_CXVSCROLL:
3925 case SM_CYHSCROLL:
3926 get_entry( &entry_SCROLLWIDTH, 0, &ret );
3927 return max( ret, 8 );
3928 case SM_CYCAPTION:
3929 ncm.cbSize = sizeof(ncm);
3930 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
3931 return ncm.iCaptionHeight + 1;
3932 case SM_CXBORDER:
3933 case SM_CYBORDER:
3934 /* SM_C{X,Y}BORDER always returns 1 regardless of 'BorderWidth' value in registry */
3935 return 1;
3936 case SM_CXDLGFRAME:
3937 case SM_CYDLGFRAME:
3938 return 3;
3939 case SM_CYVTHUMB:
3940 case SM_CXHTHUMB:
3941 case SM_CYVSCROLL:
3942 case SM_CXHSCROLL:
3943 get_entry( &entry_SCROLLHEIGHT, 0, &ret );
3944 return max( ret, 8 );
3945 case SM_CXICON:
3946 case SM_CYICON:
3947 return map_to_dpi( 32, get_system_dpi() );
3948 case SM_CXCURSOR:
3949 case SM_CYCURSOR:
3950 ret = map_to_dpi( 32, get_system_dpi() );
3951 if (ret >= 64) return 64;
3952 if (ret >= 48) return 48;
3953 return 32;
3954 case SM_CYMENU:
3955 ncm.cbSize = sizeof(ncm);
3956 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
3957 return ncm.iMenuHeight + 1;
3958 case SM_CXFULLSCREEN:
3959 /* see the remark for SM_CXMAXIMIZED, at least this formulation is correct */
3960 return get_system_metrics( SM_CXMAXIMIZED ) - 2 * get_system_metrics( SM_CXFRAME );
3961 case SM_CYFULLSCREEN:
3962 /* see the remark for SM_CYMAXIMIZED, at least this formulation is
3963 * correct */
3964 return get_system_metrics( SM_CYMAXIMIZED ) - get_system_metrics( SM_CYMIN );
3965 case SM_CYKANJIWINDOW:
3966 return 0;
3967 case SM_MOUSEPRESENT:
3968 return 1;
3969 case SM_DEBUG:
3970 return 0;
3971 case SM_SWAPBUTTON:
3972 get_entry( &entry_MOUSEBUTTONSWAP, 0, &ret );
3973 return ret;
3974 case SM_RESERVED1:
3975 case SM_RESERVED2:
3976 case SM_RESERVED3:
3977 case SM_RESERVED4:
3978 return 0;
3979 case SM_CXMIN:
3980 ncm.cbSize = sizeof(ncm);
3981 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
3982 hdc = get_display_dc();
3983 get_text_metr_size( hdc, &ncm.lfCaptionFont, NULL, &ret );
3984 release_display_dc( hdc );
3985 return 3 * ncm.iCaptionWidth + ncm.iCaptionHeight + 4 * ret +
3986 2 * get_system_metrics( SM_CXFRAME ) + 4;
3987 case SM_CYMIN:
3988 return get_system_metrics( SM_CYCAPTION ) + 2 * get_system_metrics( SM_CYFRAME );
3989 case SM_CXSIZE:
3990 get_entry( &entry_CAPTIONWIDTH, 0, &ret );
3991 return max( ret, 8 );
3992 case SM_CYSIZE:
3993 ncm.cbSize = sizeof(ncm);
3994 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
3995 return ncm.iCaptionHeight;
3996 case SM_CXFRAME:
3997 get_entry( &entry_BORDER, 0, &ret );
3998 ret = max( ret, 1 );
3999 return get_system_metrics( SM_CXDLGFRAME ) + ret;
4000 case SM_CYFRAME:
4001 get_entry( &entry_BORDER, 0, &ret );
4002 ret = max( ret, 1 );
4003 return get_system_metrics( SM_CYDLGFRAME ) + ret;
4004 case SM_CXMINTRACK:
4005 return get_system_metrics( SM_CXMIN );
4006 case SM_CYMINTRACK:
4007 return get_system_metrics( SM_CYMIN );
4008 case SM_CXDOUBLECLK:
4009 get_entry( &entry_DOUBLECLKWIDTH, 0, &ret );
4010 return ret;
4011 case SM_CYDOUBLECLK:
4012 get_entry( &entry_DOUBLECLKHEIGHT, 0, &ret );
4013 return ret;
4014 case SM_CXICONSPACING:
4015 im.cbSize = sizeof(im);
4016 NtUserSystemParametersInfo( SPI_GETICONMETRICS, sizeof(im), &im, 0 );
4017 return im.iHorzSpacing;
4018 case SM_CYICONSPACING:
4019 im.cbSize = sizeof(im);
4020 NtUserSystemParametersInfo( SPI_GETICONMETRICS, sizeof(im), &im, 0 );
4021 return im.iVertSpacing;
4022 case SM_MENUDROPALIGNMENT:
4023 NtUserSystemParametersInfo( SPI_GETMENUDROPALIGNMENT, 0, &ret, 0 );
4024 return ret;
4025 case SM_PENWINDOWS:
4026 return 0;
4027 case SM_DBCSENABLED:
4028 return get_cptable(get_acp())->MaximumCharacterSize > 1;
4029 case SM_CMOUSEBUTTONS:
4030 return 3;
4031 case SM_SECURE:
4032 return 0;
4033 case SM_CXEDGE:
4034 return get_system_metrics( SM_CXBORDER ) + 1;
4035 case SM_CYEDGE:
4036 return get_system_metrics( SM_CYBORDER ) + 1;
4037 case SM_CXMINSPACING:
4038 mm.cbSize = sizeof(mm);
4039 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
4040 return get_system_metrics( SM_CXMINIMIZED ) + mm.iHorzGap;
4041 case SM_CYMINSPACING:
4042 mm.cbSize = sizeof(mm);
4043 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
4044 return get_system_metrics( SM_CYMINIMIZED ) + mm.iVertGap;
4045 case SM_CXSMICON:
4046 case SM_CYSMICON:
4047 return map_to_dpi( 16, get_system_dpi() ) & ~1;
4048 case SM_CYSMCAPTION:
4049 ncm.cbSize = sizeof(ncm);
4050 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4051 return ncm.iSmCaptionHeight + 1;
4052 case SM_CXSMSIZE:
4053 get_entry( &entry_SMCAPTIONWIDTH, 0, &ret );
4054 return ret;
4055 case SM_CYSMSIZE:
4056 ncm.cbSize = sizeof(ncm);
4057 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4058 return ncm.iSmCaptionHeight;
4059 case SM_CXMENUSIZE:
4060 get_entry( &entry_MENUWIDTH, 0, &ret );
4061 return ret;
4062 case SM_CYMENUSIZE:
4063 ncm.cbSize = sizeof(ncm);
4064 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4065 return ncm.iMenuHeight;
4066 case SM_ARRANGE:
4067 mm.cbSize = sizeof(mm);
4068 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
4069 return mm.iArrange;
4070 case SM_CXMINIMIZED:
4071 mm.cbSize = sizeof(mm);
4072 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
4073 return mm.iWidth + 6;
4074 case SM_CYMINIMIZED:
4075 ncm.cbSize = sizeof(ncm);
4076 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4077 return ncm.iCaptionHeight + 6;
4078 case SM_CXMAXTRACK:
4079 return get_system_metrics( SM_CXVIRTUALSCREEN ) + 4 + 2 * get_system_metrics( SM_CXFRAME );
4080 case SM_CYMAXTRACK:
4081 return get_system_metrics( SM_CYVIRTUALSCREEN ) + 4 + 2 * get_system_metrics( SM_CYFRAME );
4082 case SM_CXMAXIMIZED:
4083 /* FIXME: subtract the width of any vertical application toolbars*/
4084 return get_system_metrics( SM_CXSCREEN ) + 2 * get_system_metrics( SM_CXFRAME );
4085 case SM_CYMAXIMIZED:
4086 /* FIXME: subtract the width of any horizontal application toolbars*/
4087 return get_system_metrics( SM_CYSCREEN ) + 2 * get_system_metrics( SM_CYCAPTION );
4088 case SM_NETWORK:
4089 return 3; /* FIXME */
4090 case SM_CLEANBOOT:
4091 return 0; /* 0 = ok, 1 = failsafe, 2 = failsafe + network */
4092 case SM_CXDRAG:
4093 get_entry( &entry_DRAGWIDTH, 0, &ret );
4094 return ret;
4095 case SM_CYDRAG:
4096 get_entry( &entry_DRAGHEIGHT, 0, &ret );
4097 return ret;
4098 case SM_SHOWSOUNDS:
4099 get_entry( &entry_SHOWSOUNDS, 0, &ret );
4100 return ret;
4101 case SM_CXMENUCHECK:
4102 case SM_CYMENUCHECK:
4104 TEXTMETRICW tm;
4105 ncm.cbSize = sizeof(ncm);
4106 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4107 hdc = get_display_dc();
4108 get_text_metr_size( hdc, &ncm.lfMenuFont, &tm, NULL );
4109 release_display_dc( hdc );
4110 return tm.tmHeight <= 0 ? 13 : ((tm.tmHeight + tm.tmExternalLeading + 1) / 2) * 2 - 1;
4112 case SM_SLOWMACHINE:
4113 return 0; /* Never true */
4114 case SM_MIDEASTENABLED:
4115 return 0; /* FIXME */
4116 case SM_MOUSEWHEELPRESENT:
4117 return 1;
4118 case SM_CXSCREEN:
4119 rect = get_primary_monitor_rect();
4120 return rect.right - rect.left;
4121 case SM_CYSCREEN:
4122 rect = get_primary_monitor_rect();
4123 return rect.bottom - rect.top;
4124 case SM_XVIRTUALSCREEN:
4125 rect = get_virtual_screen_rect( get_thread_dpi() );
4126 return rect.left;
4127 case SM_YVIRTUALSCREEN:
4128 rect = get_virtual_screen_rect( get_thread_dpi() );
4129 return rect.top;
4130 case SM_CXVIRTUALSCREEN:
4131 rect = get_virtual_screen_rect( get_thread_dpi() );
4132 return rect.right - rect.left;
4133 case SM_CYVIRTUALSCREEN:
4134 rect = get_virtual_screen_rect( get_thread_dpi() );
4135 return rect.bottom - rect.top;
4136 case SM_CMONITORS:
4137 if (!lock_display_devices()) return FALSE;
4138 ret = active_monitor_count();
4139 unlock_display_devices();
4140 return ret;
4141 case SM_SAMEDISPLAYFORMAT:
4142 return 1;
4143 case SM_IMMENABLED:
4144 return 0; /* FIXME */
4145 case SM_CXFOCUSBORDER:
4146 case SM_CYFOCUSBORDER:
4147 return 1;
4148 case SM_TABLETPC:
4149 case SM_MEDIACENTER:
4150 return 0;
4151 case SM_CMETRICS:
4152 return SM_CMETRICS;
4153 default:
4154 return 0;
4158 static int get_system_metrics_for_dpi( int index, unsigned int dpi )
4160 NONCLIENTMETRICSW ncm;
4161 ICONMETRICSW im;
4162 UINT ret;
4163 HDC hdc;
4165 /* some metrics are dynamic */
4166 switch (index)
4168 case SM_CXVSCROLL:
4169 case SM_CYHSCROLL:
4170 get_entry_dpi( &entry_SCROLLWIDTH, 0, &ret, dpi );
4171 return max( ret, 8 );
4172 case SM_CYCAPTION:
4173 ncm.cbSize = sizeof(ncm);
4174 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4175 return ncm.iCaptionHeight + 1;
4176 case SM_CYVTHUMB:
4177 case SM_CXHTHUMB:
4178 case SM_CYVSCROLL:
4179 case SM_CXHSCROLL:
4180 get_entry_dpi( &entry_SCROLLHEIGHT, 0, &ret, dpi );
4181 return max( ret, 8 );
4182 case SM_CXICON:
4183 case SM_CYICON:
4184 return map_to_dpi( 32, dpi );
4185 case SM_CXCURSOR:
4186 case SM_CYCURSOR:
4187 ret = map_to_dpi( 32, dpi );
4188 if (ret >= 64) return 64;
4189 if (ret >= 48) return 48;
4190 return 32;
4191 case SM_CYMENU:
4192 ncm.cbSize = sizeof(ncm);
4193 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4194 return ncm.iMenuHeight + 1;
4195 case SM_CXSIZE:
4196 get_entry_dpi( &entry_CAPTIONWIDTH, 0, &ret, dpi );
4197 return max( ret, 8 );
4198 case SM_CYSIZE:
4199 ncm.cbSize = sizeof(ncm);
4200 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4201 return ncm.iCaptionHeight;
4202 case SM_CXFRAME:
4203 get_entry_dpi( &entry_BORDER, 0, &ret, dpi );
4204 ret = max( ret, 1 );
4205 return get_system_metrics_for_dpi( SM_CXDLGFRAME, dpi ) + ret;
4206 case SM_CYFRAME:
4207 get_entry_dpi( &entry_BORDER, 0, &ret, dpi );
4208 ret = max( ret, 1 );
4209 return get_system_metrics_for_dpi( SM_CYDLGFRAME, dpi ) + ret;
4210 case SM_CXICONSPACING:
4211 im.cbSize = sizeof(im);
4212 NtUserSystemParametersInfoForDpi( SPI_GETICONMETRICS, sizeof(im), &im, 0, dpi );
4213 return im.iHorzSpacing;
4214 case SM_CYICONSPACING:
4215 im.cbSize = sizeof(im);
4216 NtUserSystemParametersInfoForDpi( SPI_GETICONMETRICS, sizeof(im), &im, 0, dpi );
4217 return im.iVertSpacing;
4218 case SM_CXSMICON:
4219 case SM_CYSMICON:
4220 return map_to_dpi( 16, dpi ) & ~1;
4221 case SM_CYSMCAPTION:
4222 ncm.cbSize = sizeof(ncm);
4223 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4224 return ncm.iSmCaptionHeight + 1;
4225 case SM_CXSMSIZE:
4226 get_entry_dpi( &entry_SMCAPTIONWIDTH, 0, &ret, dpi );
4227 return ret;
4228 case SM_CYSMSIZE:
4229 ncm.cbSize = sizeof(ncm);
4230 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4231 return ncm.iSmCaptionHeight;
4232 case SM_CXMENUSIZE:
4233 get_entry_dpi( &entry_MENUWIDTH, 0, &ret, dpi );
4234 return ret;
4235 case SM_CYMENUSIZE:
4236 ncm.cbSize = sizeof(ncm);
4237 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4238 return ncm.iMenuHeight;
4239 case SM_CXMENUCHECK:
4240 case SM_CYMENUCHECK:
4242 TEXTMETRICW tm;
4243 ncm.cbSize = sizeof(ncm);
4244 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4245 hdc = get_display_dc();
4246 get_text_metr_size( hdc, &ncm.lfMenuFont, &tm, NULL);
4247 release_display_dc( hdc );
4248 return tm.tmHeight <= 0 ? 13 : ((tm.tmHeight + tm.tmExternalLeading - 1) | 1);
4250 default:
4251 return get_system_metrics( index );
4255 static COLORREF get_sys_color( int index )
4257 COLORREF ret = 0;
4259 if (index >= 0 && index < ARRAY_SIZE( system_colors ))
4260 get_entry( &system_colors[index], 0, &ret );
4261 return ret;
4264 static HBRUSH get_55aa_brush(void)
4266 static const WORD pattern[] = { 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa };
4267 static HBRUSH brush_55aa;
4269 if (!brush_55aa)
4271 HBITMAP bitmap = NtGdiCreateBitmap( 8, 8, 1, 1, pattern );
4272 HBRUSH brush = NtGdiCreatePatternBrushInternal( bitmap, FALSE, FALSE );
4273 NtGdiDeleteObjectApp( bitmap );
4274 make_gdi_object_system( brush, TRUE );
4275 if (InterlockedCompareExchangePointer( (void **)&brush_55aa, brush, 0 ))
4277 make_gdi_object_system( brush, FALSE );
4278 NtGdiDeleteObjectApp( brush );
4281 return brush_55aa;
4284 static HBRUSH get_sys_color_brush( unsigned int index )
4286 if (index == COLOR_55AA_BRUSH) return get_55aa_brush();
4287 if (index >= ARRAY_SIZE( system_colors )) return 0;
4289 if (!system_colors[index].brush)
4291 HBRUSH brush = NtGdiCreateSolidBrush( get_sys_color( index ), NULL );
4292 make_gdi_object_system( brush, TRUE );
4293 if (InterlockedCompareExchangePointer( (void **)&system_colors[index].brush, brush, 0 ))
4295 make_gdi_object_system( brush, FALSE );
4296 NtGdiDeleteObjectApp( brush );
4299 return system_colors[index].brush;
4302 static HPEN get_sys_color_pen( unsigned int index )
4304 if (index >= ARRAY_SIZE( system_colors )) return 0;
4306 if (!system_colors[index].pen)
4308 HPEN pen = NtGdiCreatePen( PS_SOLID, 1, get_sys_color( index ), NULL );
4309 make_gdi_object_system( pen, TRUE );
4310 if (InterlockedCompareExchangePointer( (void **)&system_colors[index].pen, pen, 0 ))
4312 make_gdi_object_system( pen, FALSE );
4313 NtGdiDeleteObjectApp( pen );
4316 return system_colors[index].pen;
4319 /**********************************************************************
4320 * NtUserGetDoubleClickTime (win32u.@)
4322 UINT WINAPI NtUserGetDoubleClickTime(void)
4324 UINT time = 0;
4326 get_entry( &entry_DOUBLECLICKTIME, 0, &time );
4327 if (!time) time = 500;
4328 return time;
4331 /*************************************************************************
4332 * NtUserSetSysColors (win32u.@)
4334 BOOL WINAPI NtUserSetSysColors( INT count, const INT *colors, const COLORREF *values )
4336 int i;
4338 if (IS_INTRESOURCE(colors)) return FALSE; /* stupid app passes a color instead of an array */
4340 for (i = 0; i < count; i++)
4341 if (colors[i] >= 0 && colors[i] <= ARRAY_SIZE( system_colors ))
4342 set_entry( &system_colors[colors[i]], values[i], 0, 0 );
4344 /* Send WM_SYSCOLORCHANGE message to all windows */
4345 user_callbacks->pSendMessageTimeoutW( HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0,
4346 SMTO_ABORTIFHUNG, 2000, NULL );
4347 /* Repaint affected portions of all visible windows */
4348 user_callbacks->pRedrawWindow( 0, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW |
4349 RDW_ALLCHILDREN );
4350 return TRUE;
4354 static DPI_AWARENESS dpi_awareness;
4356 /***********************************************************************
4357 * NtUserSetProcessDpiAwarenessContext (win32u.@)
4359 BOOL WINAPI NtUserSetProcessDpiAwarenessContext( ULONG awareness, ULONG unknown )
4361 switch (awareness)
4363 case NTUSER_DPI_UNAWARE:
4364 case NTUSER_DPI_SYSTEM_AWARE:
4365 case NTUSER_DPI_PER_MONITOR_AWARE:
4366 case NTUSER_DPI_PER_MONITOR_AWARE_V2:
4367 case NTUSER_DPI_PER_UNAWARE_GDISCALED:
4368 break;
4369 default:
4370 SetLastError( ERROR_INVALID_PARAMETER );
4371 return FALSE;
4374 return !InterlockedCompareExchange( &dpi_awareness, awareness, 0 );
4377 /***********************************************************************
4378 * NtUserGetProcessDpiAwarenessContext (win32u.@)
4380 ULONG WINAPI NtUserGetProcessDpiAwarenessContext( HANDLE process )
4382 if (process && process != GetCurrentProcess())
4384 WARN( "not supported on other process %p\n", process );
4385 return NTUSER_DPI_UNAWARE;
4388 if (!dpi_awareness) return NTUSER_DPI_UNAWARE;
4389 return dpi_awareness;
4392 /***********************************************************************
4393 * NtUserCallOneParam (win32u.@)
4395 ULONG_PTR WINAPI NtUserCallOneParam( ULONG_PTR arg, ULONG code )
4397 switch(code)
4399 case NtUserGetSysColor:
4400 return get_sys_color( arg );
4401 case NtUserRealizePalette:
4402 return realize_palette( UlongToHandle(arg) );
4403 case NtUserGetSysColorBrush:
4404 return HandleToUlong( get_sys_color_brush(arg) );
4405 case NtUserGetSysColorPen:
4406 return HandleToUlong( get_sys_color_pen(arg) );
4407 case NtUserGetSystemMetrics:
4408 return get_system_metrics( arg );
4409 case NtUserGetDeskPattern:
4410 return get_entry( &entry_DESKPATTERN, 256, (WCHAR *)arg );
4411 default:
4412 FIXME( "invalid code %u\n", code );
4413 return 0;
4417 /***********************************************************************
4418 * NtUserCallTwoParam (win32u.@)
4420 ULONG_PTR WINAPI NtUserCallTwoParam( ULONG_PTR arg1, ULONG_PTR arg2, ULONG code )
4422 switch(code)
4424 case NtUserGetMonitorInfo:
4425 return get_monitor_info( UlongToHandle(arg1), (MONITORINFO *)arg2 );
4426 case NtUserGetSystemMetricsForDpi:
4427 return get_system_metrics_for_dpi( arg1, arg2 );
4428 case NtUserMirrorRgn:
4429 return mirror_window_region( UlongToHandle(arg1), UlongToHandle(arg2) );
4430 default:
4431 FIXME( "invalid code %u\n", code );
4432 return 0;