win32u: Move reply_message_result implementation from user32.
[wine.git] / dlls / win32u / sysparams.c
blobb2900ac53ad3eddaea052a473affc65c8439d378
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 <assert.h>
30 #include "ntstatus.h"
31 #define WIN32_NO_STATUS
32 #include "ntgdi_private.h"
33 #include "ntuser_private.h"
34 #include "devpropdef.h"
35 #include "wine/wingdi16.h"
36 #include "wine/server.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(system);
41 static HKEY video_key, enum_key, control_key, config_key, volatile_base_key;
43 static const WCHAR devicemap_video_keyW[] =
45 '\\','R','e','g','i','s','t','r','y',
46 '\\','M','a','c','h','i','n','e',
47 '\\','H','A','R','D','W','A','R','E',
48 '\\','D','E','V','I','C','E','M','A','P',
49 '\\','V','I','D','E','O'
52 static const WCHAR enum_keyW[] =
54 '\\','R','e','g','i','s','t','r','y',
55 '\\','M','a','c','h','i','n','e',
56 '\\','S','y','s','t','e','m',
57 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
58 '\\','E','n','u','m'
61 static const WCHAR control_keyW[] =
63 '\\','R','e','g','i','s','t','r','y',
64 '\\','M','a','c','h','i','n','e',
65 '\\','S','y','s','t','e','m',
66 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
67 '\\','C','o','n','t','r','o','l'
70 static const WCHAR config_keyW[] =
72 '\\','R','e','g','i','s','t','r','y',
73 '\\','M','a','c','h','i','n','e',
74 '\\','S','y','s','t','e','m',
75 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
76 '\\','H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s',
77 '\\','C','u','r','r','e','n','t'
80 static const WCHAR devpropkey_gpu_vulkan_uuidW[] =
82 'P','r','o','p','e','r','t','i','e','s',
83 '\\','{','2','3','3','A','9','E','F','3','-','A','F','C','4','-','4','A','B','D',
84 '-','B','5','6','4','-','C','3','2','F','2','1','F','1','5','3','5','C','}',
85 '\\','0','0','0','2'
88 static const WCHAR devpropkey_gpu_luidW[] =
90 'P','r','o','p','e','r','t','i','e','s',
91 '\\','{','6','0','B','1','9','3','C','B','-','5','2','7','6','-','4','D','0','F',
92 '-','9','6','F','C','-','F','1','7','3','A','B','A','D','3','E','C','6','}',
93 '\\','0','0','0','2'
96 static const WCHAR devpropkey_device_ispresentW[] =
98 'P','r','o','p','e','r','t','i','e','s',
99 '\\','{','5','4','0','B','9','4','7','E','-','8','B','4','0','-','4','5','B','C',
100 '-','A','8','A','2','-','6','A','0','B','8','9','4','C','B','D','A','2','}',
101 '\\','0','0','0','5'
104 static const WCHAR devpropkey_monitor_gpu_luidW[] =
106 'P','r','o','p','e','r','t','i','e','s',
107 '\\','{','C','A','0','8','5','8','5','3','-','1','6','C','E','-','4','8','A','A',
108 '-','B','1','1','4','-','D','E','9','C','7','2','3','3','4','2','2','3','}',
109 '\\','0','0','0','1'
112 static const WCHAR devpropkey_monitor_output_idW[] =
114 'P','r','o','p','e','r','t','i','e','s',
115 '\\','{','C','A','0','8','5','8','5','3','-','1','6','C','E','-','4','8','A','A',
116 '-','B','1','1','4','-','D','E','9','C','7','2','3','3','4','2','2','3','}',
117 '\\','0','0','0','2'
120 static const WCHAR wine_devpropkey_monitor_stateflagsW[] =
122 'P','r','o','p','e','r','t','i','e','s','\\',
123 '{','2','3','3','a','9','e','f','3','-','a','f','c','4','-','4','a','b','d',
124 '-','b','5','6','4','-','c','3','2','f','2','1','f','1','5','3','5','b','}',
125 '\\','0','0','0','2'
128 static const WCHAR wine_devpropkey_monitor_rcmonitorW[] =
130 'P','r','o','p','e','r','t','i','e','s','\\',
131 '{','2','3','3','a','9','e','f','3','-','a','f','c','4','-','4','a','b','d',
132 '-','b','5','6','4','-','c','3','2','f','2','1','f','1','5','3','5','b','}',
133 '\\','0','0','0','3'
136 static const WCHAR wine_devpropkey_monitor_rcworkW[] =
138 'P','r','o','p','e','r','t','i','e','s','\\',
139 '{','2','3','3','a','9','e','f','3','-','a','f','c','4','-','4','a','b','d',
140 '-','b','5','6','4','-','c','3','2','f','2','1','f','1','5','3','5','b','}',
141 '\\','0','0','0','4'
144 static const WCHAR wine_devpropkey_monitor_adapternameW[] =
146 'P','r','o','p','e','r','t','i','e','s','\\',
147 '{','2','3','3','a','9','e','f','3','-','a','f','c','4','-','4','a','b','d',
148 '-','b','5','6','4','-','c','3','2','f','2','1','f','1','5','3','5','b','}',
149 '\\','0','0','0','5'
152 static const WCHAR device_instanceW[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
153 static const WCHAR controlW[] = {'C','o','n','t','r','o','l'};
154 static const WCHAR device_parametersW[] =
155 {'D','e','v','i','c','e',' ','P','a','r','a','m','e','t','e','r','s'};
156 static const WCHAR linkedW[] = {'L','i','n','k','e','d',0};
157 static const WCHAR symbolic_link_valueW[] =
158 {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
159 static const WCHAR state_flagsW[] = {'S','t','a','t','e','F','l','a','g','s',0};
160 static const WCHAR gpu_idW[] = {'G','P','U','I','D',0};
161 static const WCHAR hardware_idW[] = {'H','a','r','d','w','a','r','e','I','D',0};
162 static const WCHAR device_descW[] = {'D','e','v','i','c','e','D','e','s','c',0};
163 static const WCHAR driver_descW[] = {'D','r','i','v','e','r','D','e','s','c',0};
164 static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
165 static const WCHAR class_guidW[] = {'C','l','a','s','s','G','U','I','D',0};
166 static const WCHAR pciW[] = {'P','C','I'};
167 static const WCHAR classW[] = {'C','l','a','s','s',0};
168 static const WCHAR displayW[] = {'D','i','s','p','l','a','y',0};
169 static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0};
170 static const WCHAR yesW[] = {'Y','e','s',0};
171 static const WCHAR noW[] = {'N','o',0};
173 static const char guid_devclass_displayA[] = "{4D36E968-E325-11CE-BFC1-08002BE10318}";
174 static const WCHAR guid_devclass_displayW[] =
175 {'{','4','D','3','6','E','9','6','8','-','E','3','2','5','-','1','1','C','E','-',
176 'B','F','C','1','-','0','8','0','0','2','B','E','1','0','3','1','8','}',0};
178 static const char guid_devclass_monitorA[] = "{4D36E96E-E325-11CE-BFC1-08002BE10318}";
179 static const WCHAR guid_devclass_monitorW[] =
180 {'{','4','D','3','6','E','9','6','E','-','E','3','2','5','-','1','1','C','E','-'
181 ,'B','F','C','1','-','0','8','0','0','2','B','E','1','0','3','1','8','}'};
183 static const WCHAR guid_devinterface_display_adapterW[] =
184 {'{','5','B','4','5','2','0','1','D','-','F','2','F','2','-','4','F','3','B','-',
185 '8','5','B','B','-','3','0','F','F','1','F','9','5','3','5','9','9','}',0};
187 static const WCHAR guid_display_device_arrivalW[] =
188 {'{','1','C','A','0','5','1','8','0','-','A','6','9','9','-','4','5','0','A','-',
189 '9','A','0','C','-','D','E','4','F','B','E','3','D','D','D','8','9','}',0};
191 static const WCHAR guid_devinterface_monitorW[] =
192 {'{','E','6','F','0','7','B','5','F','-','E','E','9','7','-','4','A','9','0','-',
193 'B','0','7','6','-','3','3','F','5','7','B','F','4','E','A','A','7','}',0};
195 #define NULLDRV_DEFAULT_HMONITOR ((HMONITOR)(UINT_PTR)(0x10000 + 1))
197 /* Cached display device information */
198 struct display_device
200 WCHAR device_name[32]; /* DeviceName in DISPLAY_DEVICEW */
201 WCHAR device_string[128]; /* DeviceString in DISPLAY_DEVICEW */
202 DWORD state_flags; /* StateFlags in DISPLAY_DEVICEW */
203 WCHAR device_id[128]; /* DeviceID in DISPLAY_DEVICEW */
204 WCHAR interface_name[128]; /* DeviceID in DISPLAY_DEVICEW when EDD_GET_DEVICE_INTERFACE_NAME is set */
205 WCHAR device_key[128]; /* DeviceKey in DISPLAY_DEVICEW */
208 struct adapter
210 struct list entry;
211 struct display_device dev;
212 unsigned int id;
213 const WCHAR *config_key;
216 struct monitor
218 struct list entry;
219 struct display_device dev;
220 struct adapter *adapter;
221 HANDLE handle;
222 unsigned int id;
223 unsigned int flags;
224 RECT rc_monitor;
225 RECT rc_work;
228 static struct list adapters = LIST_INIT(adapters);
229 static struct list monitors = LIST_INIT(monitors);
230 static INT64 last_query_display_time;
231 static pthread_mutex_t display_lock = PTHREAD_MUTEX_INITIALIZER;
233 static struct monitor virtual_monitor =
235 .handle = NULLDRV_DEFAULT_HMONITOR,
236 .flags = MONITORINFOF_PRIMARY,
237 .rc_monitor.right = 1024,
238 .rc_monitor.bottom = 768,
239 .rc_work.right = 1024,
240 .rc_work.bottom = 768,
241 .dev.state_flags = DISPLAY_DEVICE_ACTIVE | DISPLAY_DEVICE_ATTACHED,
244 /* the various registry keys that are used to store parameters */
245 enum parameter_key
247 COLORS_KEY,
248 DESKTOP_KEY,
249 KEYBOARD_KEY,
250 MOUSE_KEY,
251 METRICS_KEY,
252 SOUND_KEY,
253 VERSION_KEY,
254 SHOWSOUNDS_KEY,
255 KEYBOARDPREF_KEY,
256 SCREENREADER_KEY,
257 AUDIODESC_KEY,
258 NB_PARAM_KEYS
261 static const char *parameter_key_names[NB_PARAM_KEYS] =
263 "Control Panel\\Colors",
264 "Control Panel\\Desktop",
265 "Control Panel\\Keyboard",
266 "Control Panel\\Mouse",
267 "Control Panel\\Desktop\\WindowMetrics",
268 "Control Panel\\Sound",
269 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows",
270 "Control Panel\\Accessibility\\ShowSounds",
271 "Control Panel\\Accessibility\\Keyboard Preference",
272 "Control Panel\\Accessibility\\Blind Access",
273 "Control Panel\\Accessibility\\AudioDescription",
276 /* System parameters storage */
277 union sysparam_all_entry;
279 struct sysparam_entry
281 BOOL (*get)( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi );
282 BOOL (*set)( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags );
283 BOOL (*init)( union sysparam_all_entry *entry );
284 enum parameter_key base_key;
285 const char *regval;
286 enum parameter_key mirror_key;
287 const char *mirror;
288 BOOL loaded;
291 struct sysparam_uint_entry
293 struct sysparam_entry hdr;
294 UINT val;
297 struct sysparam_bool_entry
299 struct sysparam_entry hdr;
300 BOOL val;
303 struct sysparam_dword_entry
305 struct sysparam_entry hdr;
306 DWORD val;
309 struct sysparam_rgb_entry
311 struct sysparam_entry hdr;
312 COLORREF val;
313 HBRUSH brush;
314 HPEN pen;
317 struct sysparam_binary_entry
319 struct sysparam_entry hdr;
320 void *ptr;
321 size_t size;
324 struct sysparam_path_entry
326 struct sysparam_entry hdr;
327 WCHAR path[MAX_PATH];
330 struct sysparam_font_entry
332 struct sysparam_entry hdr;
333 UINT weight;
334 LOGFONTW val;
335 WCHAR fullname[LF_FACESIZE];
338 struct sysparam_pref_entry
340 struct sysparam_entry hdr;
341 struct sysparam_binary_entry *parent;
342 UINT offset;
343 UINT mask;
346 union sysparam_all_entry
348 struct sysparam_entry hdr;
349 struct sysparam_uint_entry uint;
350 struct sysparam_bool_entry bool;
351 struct sysparam_dword_entry dword;
352 struct sysparam_rgb_entry rgb;
353 struct sysparam_binary_entry bin;
354 struct sysparam_path_entry path;
355 struct sysparam_font_entry font;
356 struct sysparam_pref_entry pref;
359 static UINT system_dpi;
360 static RECT work_area;
362 static HDC display_dc;
363 static pthread_mutex_t display_dc_lock = PTHREAD_MUTEX_INITIALIZER;
365 static pthread_mutex_t user_mutex;
366 static unsigned int user_lock_thread, user_lock_rec;
368 void user_lock(void)
370 pthread_mutex_lock( &user_mutex );
371 if (!user_lock_rec++) user_lock_thread = GetCurrentThreadId();
374 void user_unlock(void)
376 if (!--user_lock_rec) user_lock_thread = 0;
377 pthread_mutex_unlock( &user_mutex );
380 void user_check_not_lock(void)
382 if (user_lock_thread == GetCurrentThreadId())
384 ERR( "BUG: holding USER lock\n" );
385 assert( 0 );
389 static HANDLE get_display_device_init_mutex( void )
391 static const WCHAR display_device_initW[] =
392 {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s',
393 '\\','d','i','s','p','l','a','y','_','d','e','v','i','c','e','_','i','n','i','t'};
394 UNICODE_STRING name = { sizeof(display_device_initW), sizeof(display_device_initW),
395 (WCHAR *)display_device_initW };
396 OBJECT_ATTRIBUTES attr;
397 HANDLE mutex;
399 InitializeObjectAttributes( &attr, &name, OBJ_OPENIF, NULL, NULL );
400 if (NtCreateMutant( &mutex, MUTEX_ALL_ACCESS, &attr, FALSE ) < 0) return 0;
401 NtWaitForSingleObject( mutex, FALSE, NULL );
402 return mutex;
405 static void release_display_device_init_mutex( HANDLE mutex )
407 NtReleaseMutant( mutex, NULL );
408 NtClose( mutex );
411 static BOOL read_display_adapter_settings( unsigned int index, struct adapter *info )
413 char buffer[4096];
414 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
415 WCHAR *value_str = (WCHAR *)value->Data;
416 HKEY hkey;
417 DWORD size;
419 if (!enum_key && !(enum_key = reg_open_key( NULL, enum_keyW, sizeof(enum_keyW) )))
420 return FALSE;
422 /* Find adapter */
423 sprintf( buffer, "\\Device\\Video%d", index );
424 size = query_reg_ascii_value( video_key, buffer, value, sizeof(buffer) );
425 if (!size || value->Type != REG_SZ ||
426 value->DataLength <= sizeof("\\Registry\\Machine\\") * sizeof(WCHAR))
427 return FALSE;
429 /* DeviceKey */
430 memcpy( info->dev.device_key, value_str, value->DataLength );
431 info->config_key = info->dev.device_key + sizeof("\\Registry\\Machine\\") - 1;
433 if (!(hkey = reg_open_key( NULL, value_str, value->DataLength - sizeof(WCHAR) )))
434 return FALSE;
436 /* DeviceString */
437 if (query_reg_value( hkey, driver_descW, value, sizeof(buffer) ) && value->Type == REG_SZ)
438 memcpy( info->dev.device_string, value_str, value->DataLength );
439 NtClose( hkey );
441 /* DeviceName */
442 sprintf( buffer, "\\\\.\\DISPLAY%d", index + 1 );
443 asciiz_to_unicode( info->dev.device_name, buffer );
445 if (!(hkey = reg_open_key( config_key, info->config_key,
446 lstrlenW( info->config_key ) * sizeof(WCHAR) )))
447 return FALSE;
449 /* StateFlags */
450 if (query_reg_value( hkey, state_flagsW, value, sizeof(buffer) ) && value->Type == REG_DWORD)
451 info->dev.state_flags = *(const DWORD *)value->Data;
453 /* Interface name */
454 info->dev.interface_name[0] = 0;
456 /* DeviceID */
457 size = query_reg_value( hkey, gpu_idW, value, sizeof(buffer) );
458 NtClose( hkey );
459 if (!size || value->Type != REG_SZ) return FALSE;
461 if (!(hkey = reg_open_key( enum_key, value_str, value->DataLength - sizeof(WCHAR) )))
462 return FALSE;
464 size = query_reg_value( hkey, hardware_idW, value, sizeof(buffer) );
465 NtClose( hkey );
466 if (!size || (value->Type != REG_SZ && value->Type != REG_MULTI_SZ))
467 return FALSE;
469 lstrcpyW( info->dev.device_id, value_str );
470 return TRUE;
473 static unsigned int query_reg_subkey_value( HKEY hkey, const WCHAR *name, unsigned int name_size,
474 KEY_VALUE_PARTIAL_INFORMATION *value, unsigned int size )
476 HKEY subkey;
478 if (!(subkey = reg_open_key( hkey, name, name_size ))) return 0;
479 size = query_reg_value( subkey, NULL, value, size );
480 NtClose( subkey );
481 return size;
484 static BOOL read_monitor_settings( struct adapter *adapter, DWORD index, struct monitor *monitor )
486 char buffer[4096];
487 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
488 WCHAR *device_name, *value_str = (WCHAR *)value->Data, *ptr;
489 HKEY hkey;
490 DWORD size, len;
492 monitor->flags = adapter->id ? 0 : MONITORINFOF_PRIMARY;
494 /* DeviceName */
495 sprintf( buffer, "\\\\.\\DISPLAY%d\\Monitor%d", adapter->id + 1, index );
496 asciiz_to_unicode( monitor->dev.device_name, buffer );
498 if (!(hkey = reg_open_key( config_key, adapter->config_key,
499 lstrlenW( adapter->config_key ) * sizeof(WCHAR) )))
500 return FALSE;
502 /* Interface name */
503 sprintf( buffer, "MonitorID%u", index );
504 size = query_reg_ascii_value( hkey, buffer, value, sizeof(buffer) );
505 NtClose( hkey );
506 if (!size || value->Type != REG_SZ) return FALSE;
507 len = asciiz_to_unicode( monitor->dev.interface_name, "\\\\\?\\" ) / sizeof(WCHAR) - 1;
508 memcpy( monitor->dev.interface_name + len, value_str, value->DataLength - sizeof(WCHAR) );
509 len += value->DataLength / sizeof(WCHAR) - 1;
510 monitor->dev.interface_name[len++] = '#';
511 memcpy( monitor->dev.interface_name + len, guid_devinterface_monitorW,
512 sizeof(guid_devinterface_monitorW) );
514 /* Replace '\\' with '#' after prefix */
515 for (ptr = monitor->dev.interface_name + ARRAYSIZE("\\\\\?\\") - 1; *ptr; ptr++)
516 if (*ptr == '\\') *ptr = '#';
518 if (!(hkey = reg_open_key( enum_key, value_str, value->DataLength - sizeof(WCHAR) )))
519 return FALSE;
521 /* StateFlags, WINE_DEVPROPKEY_MONITOR_STATEFLAGS */
522 size = query_reg_subkey_value( hkey, wine_devpropkey_monitor_stateflagsW,
523 sizeof(wine_devpropkey_monitor_stateflagsW),
524 value, sizeof(buffer) );
525 if (size != sizeof(monitor->dev.state_flags))
527 NtClose( hkey );
528 return FALSE;
530 monitor->dev.state_flags = *(const DWORD *)value->Data;
532 /* rc_monitor, WINE_DEVPROPKEY_MONITOR_RCMONITOR */
533 size = query_reg_subkey_value( hkey, wine_devpropkey_monitor_rcmonitorW,
534 sizeof(wine_devpropkey_monitor_rcmonitorW),
535 value, sizeof(buffer) );
536 if (size != sizeof(monitor->rc_monitor))
538 NtClose( hkey );
539 return FALSE;
541 monitor->rc_monitor = *(const RECT *)value->Data;
543 /* rc_work, WINE_DEVPROPKEY_MONITOR_RCWORK */
544 size = query_reg_subkey_value( hkey, wine_devpropkey_monitor_rcworkW,
545 sizeof(wine_devpropkey_monitor_rcworkW),
546 value, sizeof(buffer) );
547 if (size != sizeof(monitor->rc_work))
549 NtClose( hkey );
550 return FALSE;
552 monitor->rc_work = *(const RECT *)value->Data;
554 /* DeviceString */
555 if (!query_reg_value( hkey, device_descW, value, sizeof(buffer) ) || value->Type != REG_SZ)
557 NtClose( hkey );
558 return FALSE;
560 memcpy( monitor->dev.device_string, value->Data, value->DataLength );
562 /* DeviceKey */
563 if (!query_reg_value( hkey, driverW, value, sizeof(buffer) ) || value->Type != REG_SZ)
565 NtClose( hkey );
566 return FALSE;
568 size = asciiz_to_unicode( monitor->dev.device_key,
569 "\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\" );
570 device_name = &monitor->dev.device_key[size / sizeof(WCHAR) - 1];
571 memcpy( device_name, value_str, value->DataLength );
573 /* DeviceID */
574 if (!query_reg_value( hkey, hardware_idW, value, sizeof(buffer) ) ||
575 (value->Type != REG_SZ && value->Type != REG_MULTI_SZ))
577 NtClose( hkey );
578 return FALSE;
580 size = lstrlenW( value_str );
581 memcpy( monitor->dev.device_id, value_str, size * sizeof(WCHAR) );
582 monitor->dev.device_id[size++] = '\\';
583 lstrcpyW( monitor->dev.device_id + size, device_name );
585 NtClose( hkey );
586 return TRUE;
589 static void reg_empty_key( HKEY root, const char *key_name )
591 char buffer[4096];
592 KEY_NODE_INFORMATION *key = (KEY_NODE_INFORMATION *)buffer;
593 KEY_VALUE_FULL_INFORMATION *value = (KEY_VALUE_FULL_INFORMATION *)buffer;
594 WCHAR bufferW[512];
595 DWORD size;
596 HKEY hkey;
598 if (key_name)
599 hkey = reg_open_key( root, bufferW, asciiz_to_unicode( bufferW, key_name ) - sizeof(WCHAR) );
600 else
601 hkey = root;
603 while (!NtEnumerateKey( hkey, 0, KeyNodeInformation, key, sizeof(buffer), &size ))
604 reg_delete_tree( hkey, key->Name, key->NameLength );
606 while (!NtEnumerateValueKey( hkey, 0, KeyValueFullInformation, value, sizeof(buffer), &size ))
608 UNICODE_STRING name = { value->NameLength, value->NameLength, value->Name };
609 NtDeleteValueKey( hkey, &name );
612 if (hkey != root) NtClose( hkey );
615 static void prepare_devices(void)
617 char buffer[4096];
618 KEY_NODE_INFORMATION *key = (void *)buffer;
619 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
620 WCHAR *value_str = (WCHAR *)value->Data;
621 WCHAR bufferW[128];
622 unsigned i = 0;
623 DWORD size;
624 HKEY hkey, subkey, device_key, prop_key;
626 if (!enum_key) enum_key = reg_create_key( NULL, enum_keyW, sizeof(enum_keyW), 0, NULL );
627 if (!control_key) control_key = reg_create_key( NULL, control_keyW, sizeof(control_keyW), 0, NULL );
628 if (!video_key) video_key = reg_create_key( NULL, devicemap_video_keyW, sizeof(devicemap_video_keyW),
629 REG_OPTION_VOLATILE, NULL );
631 /* delete monitors */
632 reg_empty_key( enum_key, "DISPLAY\\DEFAULT_MONITOR" );
633 sprintf( buffer, "Class\\%s", guid_devclass_monitorA );
634 hkey = reg_create_key( control_key, bufferW, asciiz_to_unicode( bufferW, buffer ) - sizeof(WCHAR),
635 0, NULL );
636 reg_empty_key( hkey, NULL );
637 set_reg_value( hkey, classW, REG_SZ, monitorW, sizeof(monitorW) );
638 NtClose( hkey );
640 /* delete adapters */
641 reg_empty_key( video_key, NULL );
643 /* clean GPUs */
644 sprintf( buffer, "Class\\%s", guid_devclass_displayA );
645 hkey = reg_create_key( control_key, bufferW, asciiz_to_unicode( bufferW, buffer ) - sizeof(WCHAR),
646 0, NULL );
647 reg_empty_key( hkey, NULL );
648 set_reg_value( hkey, classW, REG_SZ, displayW, sizeof(displayW) );
649 NtClose( hkey );
651 hkey = reg_open_key( enum_key, pciW, sizeof(pciW) );
653 /* To preserve GPU GUIDs, mark them as not present and delete them in cleanup_devices if needed. */
654 while (!NtEnumerateKey( hkey, i++, KeyNodeInformation, key, sizeof(buffer), &size ))
656 unsigned int j = 0;
658 if (!(subkey = reg_open_key( hkey, key->Name, key->NameLength ))) continue;
660 while (!NtEnumerateKey( subkey, j++, KeyNodeInformation, key, sizeof(buffer), &size ))
662 if (!(device_key = reg_open_key( subkey, key->Name, key->NameLength ))) continue;
663 size = query_reg_value( device_key, class_guidW, value, sizeof(buffer) );
664 if (size != sizeof(guid_devclass_displayW) || wcscmp( value_str, guid_devclass_displayW ))
666 NtClose( device_key );
667 continue;
670 size = query_reg_value( device_key, class_guidW, value, sizeof(buffer) );
671 if (size == sizeof(guid_devclass_displayW) &&
672 !wcscmp( (const WCHAR *)value->Data, guid_devclass_displayW ) &&
673 (prop_key = reg_create_key( device_key, devpropkey_device_ispresentW,
674 sizeof(devpropkey_device_ispresentW), 0, NULL )))
676 BOOL present = FALSE;
677 set_reg_value( prop_key, NULL, 0xffff0000 | DEVPROP_TYPE_BOOLEAN,
678 &present, sizeof(present) );
679 NtClose( prop_key );
682 NtClose( device_key );
685 NtClose( subkey );
688 NtClose( hkey );
691 static void cleanup_devices(void)
693 char buffer[4096];
694 KEY_NODE_INFORMATION *key = (void *)buffer;
695 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
696 WCHAR bufferW[512], *value_str = (WCHAR *)value->Data;
697 unsigned i = 0;
698 DWORD size;
699 HKEY hkey, subkey, device_key, prop_key;
701 hkey = reg_open_key( enum_key, pciW, sizeof(pciW) );
703 restart:
704 while (!NtEnumerateKey( hkey, i++, KeyNodeInformation, key, sizeof(buffer), &size ))
706 unsigned int j = 0;
708 if (!(subkey = reg_open_key( hkey, key->Name, key->NameLength ))) continue;
710 while (!NtEnumerateKey( subkey, j++, KeyNodeInformation, key, sizeof(buffer), &size ))
712 BOOL present = FALSE;
714 if (!(device_key = reg_open_key( subkey, key->Name, key->NameLength ))) continue;
715 memcpy( bufferW, key->Name, key->NameLength );
716 bufferW[key->NameLength / sizeof(WCHAR)] = 0;
718 size = query_reg_value( device_key, class_guidW, value, sizeof(buffer) );
719 if (size != sizeof(guid_devclass_displayW) || wcscmp( value_str, guid_devclass_displayW ))
721 NtClose( device_key );
722 continue;
725 if ((prop_key = reg_open_key( device_key, devpropkey_device_ispresentW,
726 sizeof(devpropkey_device_ispresentW) )))
728 if (query_reg_value( prop_key, NULL, value, sizeof(buffer) ) == sizeof(BOOL))
729 present = *(const BOOL *)value->Data;
730 NtClose( prop_key );
733 NtClose( device_key );
735 if (!present && reg_delete_tree( subkey, bufferW, lstrlenW( bufferW ) * sizeof(WCHAR) ))
736 goto restart;
739 NtClose( subkey );
742 NtClose( hkey );
745 /* see UuidCreate */
746 static void uuid_create( GUID *uuid )
748 char buf[4096];
749 NtQuerySystemInformation( SystemInterruptInformation, buf, sizeof(buf), NULL );
750 memcpy( uuid, buf, sizeof(*uuid) );
751 uuid->Data3 &= 0x0fff;
752 uuid->Data3 |= (4 << 12);
753 uuid->Data4[0] &= 0x3f;
754 uuid->Data4[0] |= 0x80;
757 #define TICKSPERSEC 10000000
758 #define SECSPERDAY 86400
759 #define DAYSPERQUADRICENTENNIUM (365 * 400 + 97)
760 #define DAYSPERNORMALQUADRENNIUM (365 * 4 + 1)
762 static unsigned int format_date( WCHAR *bufferW, LONGLONG time )
764 int cleaps, years, yearday, months, days;
765 unsigned int day, month, year;
766 char buffer[32];
768 days = time / TICKSPERSEC / SECSPERDAY;
770 /* compute year, month and day of month, see RtlTimeToTimeFields */
771 cleaps = (3 * ((4 * days + 1227) / DAYSPERQUADRICENTENNIUM) + 3) / 4;
772 days += 28188 + cleaps;
773 years = (20 * days - 2442) / (5 * DAYSPERNORMALQUADRENNIUM);
774 yearday = days - (years * DAYSPERNORMALQUADRENNIUM) / 4;
775 months = (64 * yearday) / 1959;
776 if (months < 14)
778 month = months - 1;
779 year = years + 1524;
781 else
783 month = months - 13;
784 year = years + 1525;
786 day = yearday - (1959 * months) / 64 ;
788 sprintf( buffer, "%u-%u-%u", month, day, year );
789 return asciiz_to_unicode( bufferW, buffer );
792 struct device_manager_ctx
794 unsigned int gpu_count;
795 unsigned int adapter_count;
796 unsigned int video_count;
797 unsigned int monitor_count;
798 unsigned int output_count;
799 HANDLE mutex;
800 WCHAR gpuid[128];
801 WCHAR gpu_guid[64];
802 LUID gpu_luid;
803 HKEY adapter_key;
804 BOOL virtual_monitor;
807 static void link_device( const WCHAR *instance, const WCHAR *class )
809 unsigned int instance_len = lstrlenW( instance ), len;
810 unsigned int class_len = lstrlenW( class );
811 WCHAR buffer[MAX_PATH], *ptr;
812 HKEY hkey, subkey;
814 static const WCHAR symbolic_linkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
815 static const WCHAR hashW[] = {'#'};
817 len = asciiz_to_unicode( buffer, "DeviceClasses\\" ) / sizeof(WCHAR) - 1;
818 memcpy( buffer + len, class, class_len * sizeof(WCHAR) );
819 len += class_len;
820 len += asciiz_to_unicode( buffer + len, "\\##?#" ) / sizeof(WCHAR) - 1;
821 memcpy( buffer + len, instance, instance_len * sizeof(WCHAR) );
822 for (ptr = buffer + len; *ptr; ptr++) if (*ptr == '\\') *ptr = '#';
823 len += instance_len;
824 buffer[len++] = '#';
825 memcpy( buffer + len, class, class_len * sizeof(WCHAR) );
826 len += class_len;
827 hkey = reg_create_key( control_key, buffer, len * sizeof(WCHAR), 0, NULL );
829 set_reg_value( hkey, device_instanceW, REG_SZ, instance, (instance_len + 1) * sizeof(WCHAR) );
831 subkey = reg_create_key( hkey, hashW, sizeof(hashW), REG_OPTION_VOLATILE, NULL );
832 NtClose( hkey );
833 hkey = subkey;
835 len = asciiz_to_unicode( buffer, "\\\\?\\" ) / sizeof(WCHAR) - 1;
836 memcpy( buffer + len, instance, (instance_len + 1) * sizeof(WCHAR) );
837 len += instance_len;
838 memcpy( buffer + len, class, (class_len + 1) * sizeof(WCHAR) );
839 len += class_len + 1;
840 for (ptr = buffer + 4; *ptr; ptr++) if (*ptr == '\\') *ptr = '#';
841 set_reg_value( hkey, symbolic_linkW, REG_SZ, buffer, len * sizeof(WCHAR) );
843 if ((subkey = reg_create_key( hkey, controlW, sizeof(controlW), REG_OPTION_VOLATILE, NULL )))
845 const DWORD linked = 1;
846 set_reg_value( subkey, linkedW, REG_DWORD, &linked, sizeof(linked) );
847 NtClose( subkey );
851 static void add_gpu( const struct gdi_gpu *gpu, void *param )
853 struct device_manager_ctx *ctx = param;
854 const WCHAR *desc;
855 char buffer[4096];
856 WCHAR bufferW[512];
857 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
858 unsigned int gpu_index, size;
859 HKEY hkey, subkey;
860 LARGE_INTEGER ft;
862 static const BOOL present = TRUE;
863 static const WCHAR wine_adapterW[] = {'W','i','n','e',' ','A','d','a','p','t','e','r',0};
864 static const WCHAR video_idW[] = {'V','i','d','e','o','I','D',0};
865 static const WCHAR driver_date_dataW[] =
866 {'D','r','i','v','e','r','D','a','t','e','D','a','t','a',0};
867 static const WCHAR adapter_stringW[] =
868 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n',
869 '.','A','d','a','p','t','e','r','S','t','r','i','n','g',0};
870 static const WCHAR bios_stringW[] =
871 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n','.',
872 'B','i','o','s','S','t','r','i','n','g',0};
873 static const WCHAR chip_typeW[] =
874 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n','.',
875 'C','h','i','p','T','y','p','e',0};
876 static const WCHAR dac_typeW[] =
877 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n','.',
878 'D','a','c','T','y','p','e',0};
879 static const WCHAR ramdacW[] =
880 {'I','n','t','e','r','g','r','a','t','e','d',' ','R','A','M','D','A','C',0};
881 static const WCHAR driver_dateW[] = {'D','r','i','v','e','r','D','a','t','e',0};
883 TRACE( "%s %04X %04X %08X %02X\n", debugstr_w(gpu->name),
884 gpu->vendor_id, gpu->device_id, gpu->subsys_id, gpu->revision_id );
886 gpu_index = ctx->gpu_count++;
887 ctx->adapter_count = 0;
888 ctx->monitor_count = 0;
890 if (!enum_key && !(enum_key = reg_create_key( NULL, enum_keyW, sizeof(enum_keyW), 0, NULL )))
891 return;
893 if (!ctx->mutex)
895 ctx->mutex = get_display_device_init_mutex();
896 pthread_mutex_lock( &display_lock );
897 prepare_devices();
900 sprintf( buffer, "PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X\\%08X",
901 gpu->vendor_id, gpu->device_id, gpu->subsys_id, gpu->revision_id, gpu_index );
902 size = asciiz_to_unicode( ctx->gpuid, buffer );
903 if (!(hkey = reg_create_key( enum_key, ctx->gpuid, size - sizeof(WCHAR), 0, NULL ))) return;
905 set_reg_value( hkey, classW, REG_SZ, displayW, sizeof(displayW) );
906 set_reg_value( hkey, class_guidW, REG_SZ, guid_devclass_displayW,
907 sizeof(guid_devclass_displayW) );
908 sprintf( buffer, "%s\\%04X", guid_devclass_displayA, gpu_index );
909 set_reg_value( hkey, driverW, REG_SZ, bufferW, asciiz_to_unicode( bufferW, buffer ));
911 sprintf( buffer, "PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X",
912 gpu->vendor_id, gpu->device_id, gpu->subsys_id, gpu->revision_id );
913 size = asciiz_to_unicode( bufferW, buffer );
914 bufferW[size / sizeof(WCHAR)] = 0; /* for REG_MULTI_SZ */
915 set_reg_value( hkey, hardware_idW, REG_MULTI_SZ, bufferW, size + sizeof(WCHAR) );
917 desc = gpu->name;
918 if (!desc[0]) desc = wine_adapterW;
919 set_reg_value( hkey, device_descW, REG_SZ, desc, (lstrlenW( desc ) + 1) * sizeof(WCHAR) );
921 if ((subkey = reg_create_key( hkey, device_parametersW, sizeof(device_parametersW), 0, NULL )))
923 if (!query_reg_value( subkey, video_idW, value, sizeof(buffer) ))
925 GUID guid;
926 uuid_create( &guid );
927 sprintf( buffer, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
928 (unsigned int)guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2],
929 guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7] );
930 size = asciiz_to_unicode( ctx->gpu_guid, buffer );
931 TRACE( "created guid %s\n", debugstr_w(ctx->gpu_guid) );
932 set_reg_value( subkey, video_idW, REG_SZ, ctx->gpu_guid, size );
934 else
936 memcpy( ctx->gpu_guid, value->Data, value->DataLength );
937 TRACE( "got guid %s\n", debugstr_w(ctx->gpu_guid) );
939 NtClose( subkey );
942 if ((subkey = reg_create_key( hkey, devpropkey_gpu_vulkan_uuidW,
943 sizeof(devpropkey_gpu_vulkan_uuidW), 0, NULL )))
945 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_GUID,
946 &gpu->vulkan_uuid, sizeof(gpu->vulkan_uuid) );
947 NtClose( subkey );
950 if ((subkey = reg_create_key( hkey, devpropkey_device_ispresentW,
951 sizeof(devpropkey_device_ispresentW), 0, NULL )))
953 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_BOOLEAN,
954 &present, sizeof(present) );
955 NtClose( subkey );
958 if ((subkey = reg_create_key( hkey, devpropkey_gpu_luidW, sizeof(devpropkey_gpu_luidW), 0, NULL )))
960 if (query_reg_value( subkey, NULL, value, sizeof(buffer) ) != sizeof(LUID))
962 NtAllocateLocallyUniqueId( &ctx->gpu_luid );
963 TRACE("allocated luid %08x%08x\n", ctx->gpu_luid.HighPart, ctx->gpu_luid.LowPart );
964 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_UINT64,
965 &ctx->gpu_luid, sizeof(ctx->gpu_luid) );
967 else
969 memcpy( &ctx->gpu_luid, value->Data, sizeof(ctx->gpu_luid) );
970 TRACE("got luid %08x%08x\n", ctx->gpu_luid.HighPart, ctx->gpu_luid.LowPart );
972 NtClose( subkey );
975 NtClose( hkey );
977 sprintf( buffer, "Class\\%s\\%04X", guid_devclass_displayA, gpu_index );
978 hkey = reg_create_key( control_key, bufferW,
979 asciiz_to_unicode( bufferW, buffer ) - sizeof(WCHAR), 0, NULL );
981 NtQuerySystemTime( &ft );
982 set_reg_value( hkey, driver_dateW, REG_SZ, bufferW, format_date( bufferW, ft.QuadPart ));
984 set_reg_value( hkey, driver_date_dataW, REG_BINARY, &ft, sizeof(ft) );
986 size = (lstrlenW( desc ) + 1) * sizeof(WCHAR);
987 set_reg_value( hkey, driver_descW, REG_SZ, desc, size );
988 set_reg_value( hkey, adapter_stringW, REG_BINARY, desc, size );
989 set_reg_value( hkey, bios_stringW, REG_BINARY, desc, size );
990 set_reg_value( hkey, chip_typeW, REG_BINARY, desc, size );
991 set_reg_value( hkey, dac_typeW, REG_BINARY, ramdacW, sizeof(ramdacW) );
993 NtClose( hkey );
995 link_device( ctx->gpuid, guid_devinterface_display_adapterW );
996 link_device( ctx->gpuid, guid_display_device_arrivalW );
999 static void add_adapter( const struct gdi_adapter *adapter, void *param )
1001 struct device_manager_ctx *ctx = param;
1002 unsigned int adapter_index, video_index, len;
1003 char name[64], buffer[MAX_PATH];
1004 WCHAR nameW[64], bufferW[MAX_PATH];
1005 HKEY hkey;
1007 TRACE( "\n" );
1009 if (!ctx->gpu_count)
1011 static const struct gdi_gpu default_gpu;
1012 TRACE( "adding default fake GPU\n" );
1013 add_gpu( &default_gpu, ctx );
1016 if (ctx->adapter_key)
1018 NtClose( ctx->adapter_key );
1019 ctx->adapter_key = NULL;
1022 adapter_index = ctx->adapter_count++;
1023 video_index = ctx->video_count++;
1024 ctx->monitor_count = 0;
1026 len = asciiz_to_unicode( bufferW, "\\Registry\\Machine\\System\\CurrentControlSet\\"
1027 "Control\\Video\\" ) / sizeof(WCHAR) - 1;
1028 lstrcpyW( bufferW + len, ctx->gpu_guid );
1029 len += lstrlenW( bufferW + len );
1030 sprintf( buffer, "\\%04x", adapter_index );
1031 len += asciiz_to_unicode( bufferW + len, buffer ) / sizeof(WCHAR) - 1;
1032 hkey = reg_create_key( NULL, bufferW, len * sizeof(WCHAR),
1033 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK, NULL );
1034 if (!hkey) hkey = reg_create_key( NULL, bufferW, len * sizeof(WCHAR),
1035 REG_OPTION_VOLATILE | REG_OPTION_OPEN_LINK, NULL );
1037 sprintf( name, "\\Device\\Video%u", video_index );
1038 asciiz_to_unicode( nameW, name );
1039 set_reg_value( video_key, nameW, REG_SZ, bufferW, (lstrlenW( bufferW ) + 1) * sizeof(WCHAR) );
1041 if (hkey)
1043 sprintf( buffer, "\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\"
1044 "%s\\%04X", guid_devclass_displayA, ctx->gpu_count - 1 );
1045 len = asciiz_to_unicode( bufferW, buffer ) - sizeof(WCHAR);
1046 set_reg_value( hkey, symbolic_link_valueW, REG_LINK, bufferW, len );
1047 NtClose( hkey );
1049 else ERR( "failed to create link key\n" );
1051 /* Following information is Wine specific, it doesn't really exist on Windows. */
1052 len = asciiz_to_unicode( bufferW, "System\\CurrentControlSet\\Control\\Video\\" )
1053 / sizeof(WCHAR) - 1;
1054 lstrcpyW( bufferW + len, ctx->gpu_guid );
1055 len += lstrlenW( bufferW + len );
1056 sprintf( buffer, "\\%04x", adapter_index );
1057 len += asciiz_to_unicode( bufferW + len, buffer ) / sizeof(WCHAR) - 1;
1058 ctx->adapter_key = reg_create_key( config_key, bufferW, len * sizeof(WCHAR),
1059 REG_OPTION_VOLATILE, NULL );
1061 set_reg_value( ctx->adapter_key, gpu_idW, REG_SZ, ctx->gpuid,
1062 (lstrlenW( ctx->gpuid ) + 1) * sizeof(WCHAR) );
1063 set_reg_value( ctx->adapter_key, state_flagsW, REG_DWORD, &adapter->state_flags,
1064 sizeof(adapter->state_flags) );
1067 static void add_monitor( const struct gdi_monitor *monitor, void *param )
1069 struct device_manager_ctx *ctx = param;
1070 char buffer[MAX_PATH], instance[64];
1071 unsigned int monitor_index, output_index;
1072 WCHAR bufferW[MAX_PATH];
1073 HKEY hkey, subkey;
1075 static const WCHAR default_monitorW[] =
1076 {'M','O','N','I','T','O','R','\\','D','e','f','a','u','l','t','_','M','o','n','i','t','o','r',0,0};
1078 if (!monitor)
1080 ctx->virtual_monitor = TRUE;
1081 return;
1084 TRACE( "%s %s %s\n", debugstr_w(monitor->name), wine_dbgstr_rect(&monitor->rc_monitor),
1085 wine_dbgstr_rect(&monitor->rc_work) );
1087 if (!ctx->adapter_count)
1089 static const struct gdi_adapter default_adapter =
1091 .state_flags = DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_PRIMARY_DEVICE |
1092 DISPLAY_DEVICE_VGA_COMPATIBLE,
1094 TRACE( "adding default fake adapter\n" );
1095 add_adapter( &default_adapter, ctx );
1098 monitor_index = ctx->monitor_count++;
1099 output_index = ctx->output_count++;
1101 sprintf( buffer, "MonitorID%u", monitor_index );
1102 sprintf( instance, "DISPLAY\\Default_Monitor\\%04X&%04X", ctx->video_count - 1, monitor_index );
1103 set_reg_ascii_value( ctx->adapter_key, buffer, instance );
1105 hkey = reg_create_key( enum_key, bufferW, asciiz_to_unicode( bufferW, instance ) - sizeof(WCHAR),
1106 0, NULL );
1107 if (!hkey) return;
1109 link_device( bufferW, guid_devinterface_monitorW );
1111 lstrcpyW( bufferW, monitor->name );
1112 if (!bufferW[0]) asciiz_to_unicode( bufferW, "Generic Non-PnP Monitor" );
1113 set_reg_value( hkey, device_descW, REG_SZ, bufferW, (lstrlenW( bufferW ) + 1) * sizeof(WCHAR) );
1115 set_reg_value( hkey, classW, REG_SZ, monitorW, sizeof(monitorW) );
1116 sprintf( buffer, "%s\\%04X", guid_devclass_monitorA, output_index );
1117 set_reg_ascii_value( hkey, "Driver", buffer );
1118 set_reg_value( hkey, class_guidW, REG_SZ, guid_devclass_monitorW, sizeof(guid_devclass_monitorW) );
1119 set_reg_value( hkey, hardware_idW, REG_MULTI_SZ, default_monitorW, sizeof(default_monitorW) );
1121 if ((subkey = reg_create_key( hkey, device_parametersW, sizeof(device_parametersW), 0, NULL )))
1123 static const WCHAR bad_edidW[] = {'B','A','D','_','E','D','I','D',0};
1124 static const WCHAR edidW[] = {'E','D','I','D',0};
1126 if (monitor->edid_len)
1127 set_reg_value( subkey, edidW, REG_BINARY, monitor->edid, monitor->edid_len );
1128 else
1129 set_reg_value( subkey, bad_edidW, REG_BINARY, NULL, 0 );
1130 NtClose( subkey );
1133 /* StateFlags */
1134 if ((subkey = reg_create_key( hkey, wine_devpropkey_monitor_stateflagsW,
1135 sizeof(wine_devpropkey_monitor_stateflagsW), 0, NULL )))
1137 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_UINT32, &monitor->state_flags,
1138 sizeof(monitor->state_flags) );
1139 NtClose( subkey );
1142 /* WINE_DEVPROPKEY_MONITOR_RCMONITOR */
1143 if ((subkey = reg_create_key( hkey, wine_devpropkey_monitor_rcmonitorW,
1144 sizeof(wine_devpropkey_monitor_rcmonitorW), 0, NULL )))
1146 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_BINARY, &monitor->rc_monitor,
1147 sizeof(monitor->rc_monitor) );
1148 NtClose( subkey );
1151 /* WINE_DEVPROPKEY_MONITOR_RCWORK */
1152 if ((subkey = reg_create_key( hkey, wine_devpropkey_monitor_rcworkW,
1153 sizeof(wine_devpropkey_monitor_rcworkW), 0, NULL )))
1155 TRACE( "rc_work %s\n", wine_dbgstr_rect(&monitor->rc_work) );
1156 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_BINARY, &monitor->rc_work,
1157 sizeof(monitor->rc_work) );
1158 NtClose( subkey );
1161 /* WINE_DEVPROPKEY_MONITOR_ADAPTERNAME */
1162 if ((subkey = reg_create_key( hkey, wine_devpropkey_monitor_adapternameW,
1163 sizeof(wine_devpropkey_monitor_adapternameW), 0, NULL )))
1165 sprintf( buffer, "\\\\.\\DISPLAY%u", ctx->video_count );
1166 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_STRING, bufferW,
1167 asciiz_to_unicode( bufferW, buffer ));
1168 NtClose( subkey );
1171 /* DEVPROPKEY_MONITOR_GPU_LUID */
1172 if ((subkey = reg_create_key( hkey, devpropkey_monitor_gpu_luidW,
1173 sizeof(devpropkey_monitor_gpu_luidW), 0, NULL )))
1175 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_INT64,
1176 &ctx->gpu_luid, sizeof(ctx->gpu_luid) );
1177 NtClose( subkey );
1180 /* DEVPROPKEY_MONITOR_OUTPUT_ID */
1181 if ((subkey = reg_create_key( hkey, devpropkey_monitor_output_idW,
1182 sizeof(devpropkey_monitor_output_idW), 0, NULL )))
1184 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_UINT32,
1185 &output_index, sizeof(output_index) );
1186 NtClose( subkey );
1189 NtClose( hkey );
1191 sprintf( buffer, "Class\\%s\\%04X", guid_devclass_monitorA, output_index );
1192 hkey = reg_create_key( control_key, bufferW,
1193 asciiz_to_unicode( bufferW, buffer ) - sizeof(WCHAR), 0, NULL );
1194 if (hkey) NtClose( hkey );
1197 static const struct gdi_device_manager device_manager =
1199 add_gpu,
1200 add_adapter,
1201 add_monitor,
1204 static void release_display_manager_ctx( struct device_manager_ctx *ctx )
1206 if (ctx->mutex)
1208 pthread_mutex_unlock( &display_lock );
1209 release_display_device_init_mutex( ctx->mutex );
1211 if (ctx->adapter_key)
1213 NtClose( ctx->adapter_key );
1214 last_query_display_time = 0;
1216 if (ctx->gpu_count) cleanup_devices();
1219 static void clear_display_devices(void)
1221 struct adapter *adapter;
1222 struct monitor *monitor;
1224 if (list_head( &monitors ) == &virtual_monitor.entry)
1226 list_init( &monitors );
1227 return;
1230 while (!list_empty( &monitors ))
1232 monitor = LIST_ENTRY( list_head( &monitors ), struct monitor, entry );
1233 list_remove( &monitor->entry );
1234 free( monitor );
1237 while (!list_empty( &adapters ))
1239 adapter = LIST_ENTRY( list_head( &adapters ), struct adapter, entry );
1240 list_remove( &adapter->entry );
1241 free( adapter );
1245 static BOOL update_display_cache_from_registry(void)
1247 DWORD adapter_id, monitor_id, monitor_count = 0, size;
1248 KEY_FULL_INFORMATION key;
1249 struct adapter *adapter;
1250 struct monitor *monitor;
1251 HANDLE mutex = NULL;
1252 NTSTATUS status;
1253 BOOL ret;
1255 /* If user driver did initialize the registry, then exit */
1256 if (!video_key && !(video_key = reg_open_key( NULL, devicemap_video_keyW,
1257 sizeof(devicemap_video_keyW) )))
1258 return FALSE;
1260 status = NtQueryKey( video_key, KeyFullInformation, &key, sizeof(key), &size );
1261 if (status && status != STATUS_BUFFER_OVERFLOW)
1262 return FALSE;
1264 if (key.LastWriteTime.QuadPart <= last_query_display_time) return TRUE;
1266 mutex = get_display_device_init_mutex();
1267 pthread_mutex_lock( &display_lock );
1269 clear_display_devices();
1271 for (adapter_id = 0;; adapter_id++)
1273 if (!(adapter = calloc( 1, sizeof(*adapter) ))) break;
1274 adapter->id = adapter_id;
1276 if (!read_display_adapter_settings( adapter_id, adapter ))
1278 free( adapter );
1279 break;
1282 list_add_tail( &adapters, &adapter->entry );
1283 for (monitor_id = 0;; monitor_id++)
1285 if (!(monitor = calloc( 1, sizeof(*monitor) ))) break;
1286 monitor->id = monitor_id;
1287 monitor->adapter = adapter;
1289 if (!read_monitor_settings( adapter, monitor_id, monitor ))
1291 free( monitor );
1292 break;
1295 monitor->handle = UlongToHandle( ++monitor_count );
1296 list_add_tail( &monitors, &monitor->entry );
1300 if ((ret = !list_empty( &adapters ) && !list_empty( &monitors )))
1301 last_query_display_time = key.LastWriteTime.QuadPart;
1302 pthread_mutex_unlock( &display_lock );
1303 release_display_device_init_mutex( mutex );
1304 return ret;
1307 static BOOL update_display_cache(void)
1309 struct device_manager_ctx ctx = { 0 };
1311 user_driver->pUpdateDisplayDevices( &device_manager, FALSE, &ctx );
1312 release_display_manager_ctx( &ctx );
1313 if (ctx.virtual_monitor)
1315 clear_display_devices();
1316 list_add_tail( &monitors, &virtual_monitor.entry );
1317 return TRUE;
1320 if (update_display_cache_from_registry()) return TRUE;
1321 if (ctx.gpu_count)
1323 ERR( "driver reported devices, but we failed to read them\n" );
1324 return FALSE;
1327 user_driver->pUpdateDisplayDevices( &device_manager, TRUE, &ctx );
1328 release_display_manager_ctx( &ctx );
1330 if (!update_display_cache_from_registry())
1332 ERR( "failed to read display config\n" );
1333 return FALSE;
1335 return TRUE;
1338 static BOOL lock_display_devices(void)
1340 if (!update_display_cache()) return FALSE;
1341 pthread_mutex_lock( &display_lock );
1342 return TRUE;
1345 static void unlock_display_devices(void)
1347 pthread_mutex_unlock( &display_lock );
1350 static HDC get_display_dc(void)
1352 pthread_mutex_lock( &display_dc_lock );
1353 if (!display_dc)
1355 HDC dc;
1357 pthread_mutex_unlock( &display_dc_lock );
1358 dc = NtGdiOpenDCW( NULL, NULL, NULL, 0, TRUE, NULL, NULL, NULL );
1359 pthread_mutex_lock( &display_dc_lock );
1360 if (display_dc)
1361 NtGdiDeleteObjectApp( dc );
1362 else
1363 display_dc = dc;
1365 return display_dc;
1368 static void release_display_dc( HDC hdc )
1370 pthread_mutex_unlock( &display_dc_lock );
1373 /**********************************************************************
1374 * get_monitor_dpi
1376 UINT get_monitor_dpi( HMONITOR monitor )
1378 /* FIXME: use the monitor DPI instead */
1379 return system_dpi;
1382 /**********************************************************************
1383 * get_win_monitor_dpi
1385 UINT get_win_monitor_dpi( HWND hwnd )
1387 /* FIXME: use the monitor DPI instead */
1388 return system_dpi;
1391 /**********************************************************************
1392 * get_thread_dpi_awareness
1394 DPI_AWARENESS get_thread_dpi_awareness(void)
1396 struct user_thread_info *info = get_user_thread_info();
1397 ULONG_PTR context = info->dpi_awareness;
1399 if (!context) context = NtUserGetProcessDpiAwarenessContext( NULL );
1401 switch (context)
1403 case 0x10:
1404 case 0x11:
1405 case 0x12:
1406 case 0x80000010:
1407 case 0x80000011:
1408 case 0x80000012:
1409 return context & 3;
1410 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE:
1411 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE:
1412 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE:
1413 return ~context;
1414 default:
1415 return DPI_AWARENESS_INVALID;
1419 /**********************************************************************
1420 * get_thread_dpi
1422 UINT get_thread_dpi(void)
1424 switch (get_thread_dpi_awareness())
1426 case DPI_AWARENESS_UNAWARE: return USER_DEFAULT_SCREEN_DPI;
1427 case DPI_AWARENESS_SYSTEM_AWARE: return system_dpi;
1428 default: return 0; /* no scaling */
1432 /* see GetDpiForSystem */
1433 UINT get_system_dpi(void)
1435 if (get_thread_dpi_awareness() == DPI_AWARENESS_UNAWARE) return USER_DEFAULT_SCREEN_DPI;
1436 return system_dpi;
1439 /* see GetAwarenessFromDpiAwarenessContext */
1440 static DPI_AWARENESS get_awareness_from_dpi_awareness_context( DPI_AWARENESS_CONTEXT context )
1442 switch ((ULONG_PTR)context)
1444 case 0x10:
1445 case 0x11:
1446 case 0x12:
1447 case 0x80000010:
1448 case 0x80000011:
1449 case 0x80000012:
1450 return (ULONG_PTR)context & 3;
1451 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE:
1452 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE:
1453 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE:
1454 return ~(ULONG_PTR)context;
1455 default:
1456 return DPI_AWARENESS_INVALID;
1460 /* see SetThreadDpiAwarenessContext */
1461 DPI_AWARENESS_CONTEXT set_thread_dpi_awareness_context( DPI_AWARENESS_CONTEXT context )
1463 struct user_thread_info *info = get_user_thread_info();
1464 DPI_AWARENESS prev, val = get_awareness_from_dpi_awareness_context( context );
1466 if (val == DPI_AWARENESS_INVALID)
1468 SetLastError( ERROR_INVALID_PARAMETER );
1469 return 0;
1471 if (!(prev = info->dpi_awareness))
1473 prev = NtUserGetProcessDpiAwarenessContext( GetCurrentProcess() ) & 3;
1474 prev |= 0x80000010; /* restore to process default */
1476 if (((ULONG_PTR)context & ~(ULONG_PTR)0x13) == 0x80000000) info->dpi_awareness = 0;
1477 else info->dpi_awareness = val | 0x10;
1478 return ULongToHandle( prev );
1481 /**********************************************************************
1482 * map_dpi_rect
1484 RECT map_dpi_rect( RECT rect, UINT dpi_from, UINT dpi_to )
1486 if (dpi_from && dpi_to && dpi_from != dpi_to)
1488 rect.left = muldiv( rect.left, dpi_to, dpi_from );
1489 rect.top = muldiv( rect.top, dpi_to, dpi_from );
1490 rect.right = muldiv( rect.right, dpi_to, dpi_from );
1491 rect.bottom = muldiv( rect.bottom, dpi_to, dpi_from );
1493 return rect;
1496 /**********************************************************************
1497 * map_dpi_point
1499 POINT map_dpi_point( POINT pt, UINT dpi_from, UINT dpi_to )
1501 if (dpi_from && dpi_to && dpi_from != dpi_to)
1503 pt.x = muldiv( pt.x, dpi_to, dpi_from );
1504 pt.y = muldiv( pt.y, dpi_to, dpi_from );
1506 return pt;
1509 /* map value from system dpi to standard 96 dpi for storing in the registry */
1510 static int map_from_system_dpi( int val )
1512 return muldiv( val, USER_DEFAULT_SCREEN_DPI, get_system_dpi() );
1515 /* map value from 96 dpi to system or custom dpi */
1516 static int map_to_dpi( int val, UINT dpi )
1518 if (!dpi) dpi = get_system_dpi();
1519 return muldiv( val, dpi, USER_DEFAULT_SCREEN_DPI );
1522 RECT get_virtual_screen_rect( UINT dpi )
1524 struct monitor *monitor;
1525 RECT rect = {0};
1527 if (!lock_display_devices()) return rect;
1529 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
1531 union_rect( &rect, &rect, &monitor->rc_monitor );
1534 unlock_display_devices();
1536 if (dpi) rect = map_dpi_rect( rect, system_dpi, dpi );
1537 return rect;
1540 RECT get_display_rect( const WCHAR *display )
1542 struct monitor *monitor;
1543 RECT rect = {0};
1545 if (!lock_display_devices()) return rect;
1547 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
1549 if (!monitor->adapter || wcsicmp( monitor->adapter->dev.device_name, display )) continue;
1550 rect = monitor->rc_monitor;
1551 break;
1554 unlock_display_devices();
1555 return map_dpi_rect( rect, system_dpi, get_thread_dpi() );
1558 RECT get_primary_monitor_rect( UINT dpi )
1560 struct monitor *monitor;
1561 RECT rect = {0};
1563 if (!lock_display_devices()) return rect;
1565 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
1567 if (!(monitor->flags & MONITORINFOF_PRIMARY)) continue;
1568 rect = monitor->rc_monitor;
1569 break;
1572 unlock_display_devices();
1573 return map_dpi_rect( rect, system_dpi, dpi );
1576 /**********************************************************************
1577 * NtUserGetDisplayConfigBufferSizes (win32u.@)
1579 LONG WINAPI NtUserGetDisplayConfigBufferSizes( UINT32 flags, UINT32 *num_path_info,
1580 UINT32 *num_mode_info )
1582 struct monitor *monitor;
1583 UINT32 count = 0;
1585 TRACE( "(0x%x %p %p)\n", flags, num_path_info, num_mode_info );
1587 if (!num_path_info || !num_mode_info)
1588 return ERROR_INVALID_PARAMETER;
1590 *num_path_info = 0;
1592 switch (flags)
1594 case QDC_ALL_PATHS:
1595 case QDC_ONLY_ACTIVE_PATHS:
1596 case QDC_DATABASE_CURRENT:
1597 break;
1598 default:
1599 return ERROR_INVALID_PARAMETER;
1602 /* FIXME: semi-stub */
1603 if (flags != QDC_ONLY_ACTIVE_PATHS)
1604 FIXME( "only returning active paths\n" );
1606 if (lock_display_devices())
1608 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
1610 if (!(monitor->dev.state_flags & DISPLAY_DEVICE_ACTIVE))
1611 continue;
1612 count++;
1614 unlock_display_devices();
1617 *num_path_info = count;
1618 *num_mode_info = count * 2;
1619 TRACE( "returning %u paths %u modes\n", *num_path_info, *num_mode_info );
1620 return ERROR_SUCCESS;
1623 static struct adapter *find_adapter( UNICODE_STRING *name )
1625 struct adapter *adapter;
1627 LIST_FOR_EACH_ENTRY(adapter, &adapters, struct adapter, entry)
1629 if (!name || !name->Length) return adapter; /* use primary adapter */
1630 if (!wcsnicmp( name->Buffer, adapter->dev.device_name, name->Length / sizeof(WCHAR) ) &&
1631 !adapter->dev.device_name[name->Length / sizeof(WCHAR)])
1632 return adapter;
1634 return NULL;
1637 /***********************************************************************
1638 * NtUserEnumDisplayDevices (win32u.@)
1640 NTSTATUS WINAPI NtUserEnumDisplayDevices( UNICODE_STRING *device, DWORD index,
1641 DISPLAY_DEVICEW *info, DWORD flags )
1643 struct display_device *found = NULL;
1644 struct adapter *adapter;
1645 struct monitor *monitor;
1647 TRACE( "%s %u %p %#x\n", debugstr_us( device ), index, info, flags );
1649 if (!info || !info->cb) return STATUS_UNSUCCESSFUL;
1651 if (!lock_display_devices()) return STATUS_UNSUCCESSFUL;
1653 if (!device || !device->Length)
1655 /* Enumerate adapters */
1656 LIST_FOR_EACH_ENTRY(adapter, &adapters, struct adapter, entry)
1658 if (index == adapter->id)
1660 found = &adapter->dev;
1661 break;
1665 else if ((adapter = find_adapter( device )))
1667 /* Enumerate monitors */
1668 LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry)
1670 if (monitor->adapter == adapter && index == monitor->id)
1672 found = &monitor->dev;
1673 break;
1678 if (found)
1680 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceName) + sizeof(info->DeviceName))
1681 lstrcpyW( info->DeviceName, found->device_name );
1682 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceString) + sizeof(info->DeviceString))
1683 lstrcpyW( info->DeviceString, found->device_string );
1684 if (info->cb >= offsetof(DISPLAY_DEVICEW, StateFlags) + sizeof(info->StateFlags))
1685 info->StateFlags = found->state_flags;
1686 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->DeviceID))
1687 lstrcpyW( info->DeviceID, (flags & EDD_GET_DEVICE_INTERFACE_NAME)
1688 ? found->interface_name : found->device_id );
1689 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(info->DeviceKey))
1690 lstrcpyW( info->DeviceKey, found->device_key );
1692 unlock_display_devices();
1693 return found ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
1696 #define _X_FIELD(prefix, bits) \
1697 if ((fields) & prefix##_##bits) \
1699 p += sprintf( p, "%s%s", first ? "" : ",", #bits ); \
1700 first = FALSE; \
1703 static const char *_CDS_flags( DWORD fields )
1705 BOOL first = TRUE;
1706 CHAR buf[128];
1707 CHAR *p = buf;
1709 _X_FIELD(CDS, UPDATEREGISTRY)
1710 _X_FIELD(CDS, TEST)
1711 _X_FIELD(CDS, FULLSCREEN)
1712 _X_FIELD(CDS, GLOBAL)
1713 _X_FIELD(CDS, SET_PRIMARY)
1714 _X_FIELD(CDS, VIDEOPARAMETERS)
1715 _X_FIELD(CDS, ENABLE_UNSAFE_MODES)
1716 _X_FIELD(CDS, DISABLE_UNSAFE_MODES)
1717 _X_FIELD(CDS, RESET)
1718 _X_FIELD(CDS, RESET_EX)
1719 _X_FIELD(CDS, NORESET)
1721 *p = 0;
1722 return wine_dbg_sprintf( "%s", buf );
1725 static const char *_DM_fields( DWORD fields )
1727 BOOL first = TRUE;
1728 CHAR buf[128];
1729 CHAR *p = buf;
1731 _X_FIELD(DM, BITSPERPEL)
1732 _X_FIELD(DM, PELSWIDTH)
1733 _X_FIELD(DM, PELSHEIGHT)
1734 _X_FIELD(DM, DISPLAYFLAGS)
1735 _X_FIELD(DM, DISPLAYFREQUENCY)
1736 _X_FIELD(DM, POSITION)
1737 _X_FIELD(DM, DISPLAYORIENTATION)
1739 *p = 0;
1740 return wine_dbg_sprintf( "%s", buf );
1743 #undef _X_FIELD
1745 static void trace_devmode( const DEVMODEW *devmode )
1747 TRACE( "dmFields=%s ", _DM_fields(devmode->dmFields) );
1748 if (devmode->dmFields & DM_BITSPERPEL)
1749 TRACE( "dmBitsPerPel=%u ", devmode->dmBitsPerPel );
1750 if (devmode->dmFields & DM_PELSWIDTH)
1751 TRACE( "dmPelsWidth=%u ", devmode->dmPelsWidth );
1752 if (devmode->dmFields & DM_PELSHEIGHT)
1753 TRACE( "dmPelsHeight=%u ", devmode->dmPelsHeight );
1754 if (devmode->dmFields & DM_DISPLAYFREQUENCY)
1755 TRACE( "dmDisplayFrequency=%u ", devmode->dmDisplayFrequency );
1756 if (devmode->dmFields & DM_POSITION)
1757 TRACE( "dmPosition=(%d,%d) ", devmode->dmPosition.x, devmode->dmPosition.y );
1758 if (devmode->dmFields & DM_DISPLAYFLAGS)
1759 TRACE( "dmDisplayFlags=%#x ", devmode->dmDisplayFlags );
1760 if (devmode->dmFields & DM_DISPLAYORIENTATION)
1761 TRACE( "dmDisplayOrientation=%u ", devmode->dmDisplayOrientation );
1762 TRACE("\n");
1765 static BOOL is_detached_mode( const DEVMODEW *mode )
1767 return mode->dmFields & DM_POSITION &&
1768 mode->dmFields & DM_PELSWIDTH &&
1769 mode->dmFields & DM_PELSHEIGHT &&
1770 mode->dmPelsWidth == 0 &&
1771 mode->dmPelsHeight == 0;
1774 /***********************************************************************
1775 * NtUserChangeDisplaySettingsExW (win32u.@)
1777 LONG WINAPI NtUserChangeDisplaySettings( UNICODE_STRING *devname, DEVMODEW *devmode, HWND hwnd,
1778 DWORD flags, void *lparam )
1780 WCHAR device_name[CCHDEVICENAME];
1781 struct adapter *adapter;
1782 BOOL def_mode = TRUE;
1783 DEVMODEW dm;
1784 LONG ret;
1786 TRACE( "%s %p %p %#x %p\n", debugstr_us(devname), devmode, hwnd, flags, lparam );
1787 TRACE( "flags=%s\n", _CDS_flags(flags) );
1789 if ((!devname || !devname->Length) && !devmode)
1791 ret = user_driver->pChangeDisplaySettingsEx( NULL, NULL, hwnd, flags, lparam );
1792 if (ret != DISP_CHANGE_SUCCESSFUL)
1793 ERR( "Restoring all displays to their registry settings returned %d.\n", ret );
1794 return ret;
1797 if (!lock_display_devices()) return DISP_CHANGE_FAILED;
1798 if ((adapter = find_adapter( devname ))) lstrcpyW( device_name, adapter->dev.device_name );
1799 unlock_display_devices();
1800 if (!adapter)
1802 WARN( "Invalid device name %s.\n", debugstr_us(devname) );
1803 return DISP_CHANGE_BADPARAM;
1806 if (devmode)
1808 trace_devmode( devmode );
1810 if (devmode->dmSize < FIELD_OFFSET(DEVMODEW, dmICMMethod))
1811 return DISP_CHANGE_BADMODE;
1813 if (is_detached_mode(devmode) ||
1814 ((devmode->dmFields & DM_BITSPERPEL) && devmode->dmBitsPerPel) ||
1815 ((devmode->dmFields & DM_PELSWIDTH) && devmode->dmPelsWidth) ||
1816 ((devmode->dmFields & DM_PELSHEIGHT) && devmode->dmPelsHeight) ||
1817 ((devmode->dmFields & DM_DISPLAYFREQUENCY) && devmode->dmDisplayFrequency))
1818 def_mode = FALSE;
1821 if (def_mode)
1823 memset( &dm, 0, sizeof(dm) );
1824 dm.dmSize = sizeof(dm);
1825 if (!NtUserEnumDisplaySettings( devname, ENUM_REGISTRY_SETTINGS, &dm, 0 ))
1827 ERR( "Default mode not found!\n" );
1828 return DISP_CHANGE_BADMODE;
1831 TRACE( "Return to original display mode\n" );
1832 devmode = &dm;
1835 if ((devmode->dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != (DM_PELSWIDTH | DM_PELSHEIGHT))
1837 WARN( "devmode doesn't specify the resolution: %#x\n", devmode->dmFields );
1838 return DISP_CHANGE_BADMODE;
1841 if (!is_detached_mode(devmode) && (!devmode->dmPelsWidth || !devmode->dmPelsHeight))
1843 memset(&dm, 0, sizeof(dm));
1844 dm.dmSize = sizeof(dm);
1845 if (!NtUserEnumDisplaySettings( devname, ENUM_CURRENT_SETTINGS, &dm, 0 ))
1847 ERR( "Current mode not found!\n" );
1848 return DISP_CHANGE_BADMODE;
1851 if (!devmode->dmPelsWidth)
1852 devmode->dmPelsWidth = dm.dmPelsWidth;
1853 if (!devmode->dmPelsHeight)
1854 devmode->dmPelsHeight = dm.dmPelsHeight;
1857 ret = user_driver->pChangeDisplaySettingsEx( device_name, devmode, hwnd, flags, lparam );
1858 if (ret != DISP_CHANGE_SUCCESSFUL)
1859 ERR( "Changing %s display settings returned %d.\n", debugstr_us(devname), ret );
1860 return ret;
1863 /***********************************************************************
1864 * NtUserEnumDisplaySettings (win32u.@)
1866 BOOL WINAPI NtUserEnumDisplaySettings( UNICODE_STRING *device, DWORD mode,
1867 DEVMODEW *dev_mode, DWORD flags )
1869 WCHAR device_name[CCHDEVICENAME];
1870 struct adapter *adapter;
1871 BOOL ret;
1873 TRACE( "%s %#x %p %#x\n", debugstr_us(device), mode, dev_mode, flags );
1875 if (!lock_display_devices()) return FALSE;
1876 if ((adapter = find_adapter( device ))) lstrcpyW( device_name, adapter->dev.device_name );
1877 unlock_display_devices();
1878 if (!adapter)
1880 WARN( "Invalid device name %s.\n", debugstr_us(device) );
1881 return FALSE;
1884 ret = user_driver->pEnumDisplaySettingsEx( device_name, mode, dev_mode, flags );
1885 if (ret)
1886 TRACE( "device:%s mode index:%#x position:(%d,%d) resolution:%ux%u frequency:%uHz "
1887 "depth:%ubits orientation:%#x.\n", debugstr_w(device_name), mode,
1888 dev_mode->dmPosition.x, dev_mode->dmPosition.y, dev_mode->dmPelsWidth,
1889 dev_mode->dmPelsHeight, dev_mode->dmDisplayFrequency, dev_mode->dmBitsPerPel,
1890 dev_mode->dmDisplayOrientation );
1891 else
1892 WARN( "Failed to query %s display settings.\n", wine_dbgstr_w(device_name) );
1893 return ret;
1896 struct monitor_enum_info
1898 HANDLE handle;
1899 RECT rect;
1902 static unsigned int active_monitor_count(void)
1904 struct monitor *monitor;
1905 unsigned int count = 0;
1907 LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry)
1909 if ((monitor->dev.state_flags & DISPLAY_DEVICE_ACTIVE)) count++;
1911 return count;
1914 /***********************************************************************
1915 * NtUserEnumDisplayMonitors (win32u.@)
1917 BOOL WINAPI NtUserEnumDisplayMonitors( HDC hdc, RECT *rect, MONITORENUMPROC proc, LPARAM lparam )
1919 struct monitor_enum_info enum_buf[8], *enum_info = enum_buf;
1920 struct enum_display_monitor_params params;
1921 struct monitor *monitor;
1922 unsigned int count = 0, i;
1923 POINT origin;
1924 RECT limit;
1925 BOOL ret = TRUE;
1927 if (hdc)
1929 DC *dc;
1930 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
1931 origin.x = dc->attr->vis_rect.left;
1932 origin.y = dc->attr->vis_rect.top;
1933 release_dc_ptr( dc );
1934 if (NtGdiGetAppClipBox( hdc, &limit ) == ERROR) return FALSE;
1936 else
1938 origin.x = origin.y = 0;
1939 limit.left = limit.top = INT_MIN;
1940 limit.right = limit.bottom = INT_MAX;
1942 if (rect && !intersect_rect( &limit, &limit, rect )) return TRUE;
1944 if (!lock_display_devices()) return FALSE;
1946 count = list_count( &monitors );
1947 if (!count || (count > ARRAYSIZE(enum_buf) &&
1948 !(enum_info = malloc( count * sizeof(*enum_info) ))))
1950 unlock_display_devices();
1951 return FALSE;
1954 count = 0;
1955 LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry)
1957 RECT monrect;
1959 if (!(monitor->dev.state_flags & DISPLAY_DEVICE_ACTIVE)) continue;
1961 monrect = map_dpi_rect( monitor->rc_monitor, get_monitor_dpi( monitor->handle ),
1962 get_thread_dpi() );
1963 offset_rect( &monrect, -origin.x, -origin.y );
1964 if (!intersect_rect( &monrect, &monrect, &limit )) continue;
1966 enum_info[count].handle = monitor->handle;
1967 enum_info[count].rect = monrect;
1968 count++;
1971 unlock_display_devices();
1973 params.proc = proc;
1974 params.hdc = hdc;
1975 params.lparam = lparam;
1976 for (i = 0; i < count; i++)
1978 params.monitor = enum_info[i].handle;
1979 params.rect = enum_info[i].rect;
1980 if (!user32_call( NtUserCallEnumDisplayMonitor, &params, sizeof(params) ))
1982 ret = FALSE;
1983 break;
1986 if (enum_info != enum_buf) free( enum_info );
1987 return ret;
1990 BOOL get_monitor_info( HMONITOR handle, MONITORINFO *info )
1992 struct monitor *monitor;
1993 UINT dpi_from, dpi_to;
1995 if (info->cbSize != sizeof(MONITORINFOEXW) && info->cbSize != sizeof(MONITORINFO)) return FALSE;
1997 if (!lock_display_devices()) return FALSE;
1999 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
2001 if (monitor->handle != handle) continue;
2002 if (!(monitor->dev.state_flags & DISPLAY_DEVICE_ACTIVE)) break;
2004 /* FIXME: map dpi */
2005 info->rcMonitor = monitor->rc_monitor;
2006 info->rcWork = monitor->rc_work;
2007 info->dwFlags = monitor->flags;
2008 if (info->cbSize >= sizeof(MONITORINFOEXW))
2010 if (monitor->adapter)
2011 lstrcpyW( ((MONITORINFOEXW *)info)->szDevice, monitor->adapter->dev.device_name );
2012 else
2013 asciiz_to_unicode( ((MONITORINFOEXW *)info)->szDevice, "WinDisc" );
2015 unlock_display_devices();
2017 if ((dpi_to = get_thread_dpi()))
2019 dpi_from = get_monitor_dpi( handle );
2020 info->rcMonitor = map_dpi_rect( info->rcMonitor, dpi_from, dpi_to );
2021 info->rcWork = map_dpi_rect( info->rcWork, dpi_from, dpi_to );
2023 TRACE( "flags %04x, monitor %s, work %s\n", info->dwFlags,
2024 wine_dbgstr_rect(&info->rcMonitor), wine_dbgstr_rect(&info->rcWork));
2025 return TRUE;
2028 unlock_display_devices();
2029 WARN( "invalid handle %p\n", handle );
2030 SetLastError( ERROR_INVALID_MONITOR_HANDLE );
2031 return FALSE;
2034 HMONITOR monitor_from_rect( const RECT *rect, DWORD flags, UINT dpi )
2036 HMONITOR primary = 0, nearest = 0, ret = 0;
2037 UINT max_area = 0, min_distance = ~0u;
2038 struct monitor *monitor;
2039 RECT r;
2041 r = map_dpi_rect( *rect, dpi, system_dpi );
2042 if (is_rect_empty( &r ))
2044 r.right = r.left + 1;
2045 r.bottom = r.top + 1;
2048 if (!lock_display_devices()) return 0;
2050 LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry)
2052 RECT intersect;
2053 RECT monitor_rect = map_dpi_rect( monitor->rc_monitor, get_monitor_dpi( monitor->handle ),
2054 system_dpi );
2056 if (intersect_rect( &intersect, &monitor_rect, &r ))
2058 /* check for larger intersecting area */
2059 UINT area = (intersect.right - intersect.left) * (intersect.bottom - intersect.top);
2060 if (area > max_area)
2062 max_area = area;
2063 ret = monitor->handle;
2066 else if (!max_area) /* if not intersecting, check for min distance */
2068 UINT distance;
2069 UINT x, y;
2071 if (r.right <= monitor_rect.left) x = monitor_rect.left - r.right;
2072 else if (monitor_rect.right <= r.left) x = r.left - monitor_rect.right;
2073 else x = 0;
2074 if (r.bottom <= monitor_rect.top) y = monitor_rect.top - r.bottom;
2075 else if (monitor_rect.bottom <= r.top) y = r.top - monitor_rect.bottom;
2076 else y = 0;
2077 distance = x * x + y * y;
2078 if (distance < min_distance)
2080 min_distance = distance;
2081 nearest = monitor->handle;
2085 if (monitor->flags & MONITORINFOF_PRIMARY) primary = monitor->handle;
2088 unlock_display_devices();
2090 if (!ret)
2092 if (flags & MONITOR_DEFAULTTOPRIMARY) ret = primary;
2093 else if (flags & MONITOR_DEFAULTTONEAREST) ret = nearest;
2096 TRACE( "%s flags %x returning %p\n", wine_dbgstr_rect(rect), flags, ret );
2097 return ret;
2100 HMONITOR monitor_from_point( POINT pt, DWORD flags, UINT dpi )
2102 RECT rect;
2103 SetRect( &rect, pt.x, pt.y, pt.x + 1, pt.y + 1 );
2104 return monitor_from_rect( &rect, flags, dpi );
2107 /* see MonitorFromWindow */
2108 HMONITOR monitor_from_window( HWND hwnd, DWORD flags, UINT dpi )
2110 RECT rect;
2111 WINDOWPLACEMENT wp;
2113 TRACE( "(%p, 0x%08x)\n", hwnd, flags );
2115 wp.length = sizeof(wp);
2116 if (is_iconic( hwnd ) && get_window_placement( hwnd, &wp ))
2117 return monitor_from_rect( &wp.rcNormalPosition, flags, dpi );
2119 if (get_window_rect( hwnd, &rect, dpi ))
2120 return monitor_from_rect( &rect, flags, dpi );
2122 if (!(flags & (MONITOR_DEFAULTTOPRIMARY|MONITOR_DEFAULTTONEAREST))) return 0;
2123 /* retrieve the primary */
2124 SetRect( &rect, 0, 0, 1, 1 );
2125 return monitor_from_rect( &rect, flags, dpi );
2128 /***********************************************************************
2129 * NtUserGetSystemDpiForProcess (win32u.@)
2131 ULONG WINAPI NtUserGetSystemDpiForProcess( HANDLE process )
2133 if (process && process != GetCurrentProcess())
2135 FIXME( "not supported on other process %p\n", process );
2136 return 0;
2139 return system_dpi;
2142 /***********************************************************************
2143 * NtUserGetDpiForMonitor (win32u.@)
2145 BOOL WINAPI NtUserGetDpiForMonitor( HMONITOR monitor, UINT type, UINT *x, UINT *y )
2147 if (type > 2)
2149 SetLastError( ERROR_BAD_ARGUMENTS );
2150 return FALSE;
2152 if (!x || !y)
2154 SetLastError( ERROR_INVALID_ADDRESS );
2155 return FALSE;
2157 switch (get_thread_dpi_awareness())
2159 case DPI_AWARENESS_UNAWARE: *x = *y = USER_DEFAULT_SCREEN_DPI; break;
2160 case DPI_AWARENESS_SYSTEM_AWARE: *x = *y = system_dpi; break;
2161 default: *x = *y = get_monitor_dpi( monitor ); break;
2163 return TRUE;
2166 /* retrieve the cached base keys for a given entry */
2167 static BOOL get_base_keys( enum parameter_key index, HKEY *base_key, HKEY *volatile_key )
2169 static HKEY base_keys[NB_PARAM_KEYS];
2170 static HKEY volatile_keys[NB_PARAM_KEYS];
2171 WCHAR bufferW[128];
2172 HKEY key;
2174 if (!base_keys[index] && base_key)
2176 if (!(key = reg_create_key( hkcu_key, bufferW,
2177 asciiz_to_unicode( bufferW, parameter_key_names[index] ) - sizeof(WCHAR),
2178 0, NULL )))
2179 return FALSE;
2180 if (InterlockedCompareExchangePointer( (void **)&base_keys[index], key, 0 ))
2181 NtClose( key );
2183 if (!volatile_keys[index] && volatile_key)
2185 if (!(key = reg_create_key( volatile_base_key, bufferW,
2186 asciiz_to_unicode( bufferW, parameter_key_names[index] ) - sizeof(WCHAR),
2187 REG_OPTION_VOLATILE, NULL )))
2188 return FALSE;
2189 if (InterlockedCompareExchangePointer( (void **)&volatile_keys[index], key, 0 ))
2190 NtClose( key );
2192 if (base_key) *base_key = base_keys[index];
2193 if (volatile_key) *volatile_key = volatile_keys[index];
2194 return TRUE;
2197 /* load a value to a registry entry */
2198 static DWORD load_entry( struct sysparam_entry *entry, void *data, DWORD size )
2200 char buffer[4096];
2201 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
2202 DWORD count;
2203 HKEY base_key, volatile_key;
2205 if (!get_base_keys( entry->base_key, &base_key, &volatile_key )) return FALSE;
2207 if (!(count = query_reg_ascii_value( volatile_key, entry->regval, value, sizeof(buffer) )))
2208 count = query_reg_ascii_value( base_key, entry->regval, value, sizeof(buffer) );
2209 if (count > size)
2211 count = size;
2212 /* make sure strings are null-terminated */
2213 if (value->Type == REG_SZ) ((WCHAR *)value->Data)[count / sizeof(WCHAR) - 1] = 0;
2215 if (count) memcpy( data, value->Data, count );
2216 entry->loaded = TRUE;
2217 return count;
2220 /* save a value to a registry entry */
2221 static BOOL save_entry( const struct sysparam_entry *entry, const void *data, DWORD size,
2222 DWORD type, UINT flags )
2224 HKEY base_key, volatile_key;
2225 WCHAR nameW[64];
2227 asciiz_to_unicode( nameW, entry->regval );
2228 if (flags & SPIF_UPDATEINIFILE)
2230 if (!get_base_keys( entry->base_key, &base_key, &volatile_key )) return FALSE;
2231 if (!set_reg_value( base_key, nameW, type, data, size )) return FALSE;
2232 reg_delete_value( volatile_key, nameW );
2234 if (entry->mirror && get_base_keys( entry->mirror_key, &base_key, NULL ))
2236 asciiz_to_unicode( nameW, entry->mirror );
2237 set_reg_value( base_key, nameW, type, data, size );
2240 else
2242 if (!get_base_keys( entry->base_key, NULL, &volatile_key )) return FALSE;
2243 if (!set_reg_value( volatile_key, nameW, type, data, size )) return FALSE;
2245 return TRUE;
2248 /* save a string value to a registry entry */
2249 static BOOL save_entry_string( const struct sysparam_entry *entry, const WCHAR *str, UINT flags )
2251 return save_entry( entry, str, (lstrlenW(str) + 1) * sizeof(WCHAR), REG_SZ, flags );
2254 /* initialize an entry in the registry if missing */
2255 static BOOL init_entry( struct sysparam_entry *entry, const void *data, DWORD size, DWORD type )
2257 KEY_VALUE_PARTIAL_INFORMATION value;
2258 UNICODE_STRING name;
2259 WCHAR nameW[64];
2260 HKEY base_key;
2261 DWORD count;
2262 NTSTATUS status;
2264 if (!get_base_keys( entry->base_key, &base_key, NULL )) return FALSE;
2266 name.Buffer = nameW;
2267 name.MaximumLength = asciiz_to_unicode( nameW, entry->regval );
2268 name.Length = name.MaximumLength - sizeof(WCHAR);
2269 status = NtQueryValueKey( base_key, &name, KeyValuePartialInformation,
2270 &value, sizeof(value), &count );
2271 if (!status || status == STATUS_BUFFER_OVERFLOW) return TRUE;
2273 if (!set_reg_value( base_key, nameW, type, data, size )) return FALSE;
2274 if (entry->mirror && get_base_keys( entry->mirror_key, &base_key, NULL ))
2276 asciiz_to_unicode( nameW, entry->mirror );
2277 set_reg_value( base_key, nameW, type, data, size );
2279 entry->loaded = TRUE;
2280 return TRUE;
2283 /* initialize a string value in the registry if missing */
2284 static BOOL init_entry_string( struct sysparam_entry *entry, const WCHAR *str )
2286 return init_entry( entry, str, (lstrlenW(str) + 1) * sizeof(WCHAR), REG_SZ );
2289 /* set an int parameter in the registry */
2290 static BOOL set_int_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2292 WCHAR bufW[32];
2293 char buf[32];
2295 sprintf( buf, "%d", int_param );
2296 asciiz_to_unicode( bufW, buf );
2297 if (!save_entry_string( &entry->hdr, bufW, flags )) return FALSE;
2298 entry->uint.val = int_param;
2299 entry->hdr.loaded = TRUE;
2300 return TRUE;
2303 /* initialize an int parameter */
2304 static BOOL init_int_entry( union sysparam_all_entry *entry )
2306 WCHAR bufW[32];
2307 char buf[32];
2309 sprintf( buf, "%d", entry->uint.val );
2310 asciiz_to_unicode( bufW, buf );
2311 return init_entry_string( &entry->hdr, bufW );
2314 /* load a uint parameter from the registry */
2315 static BOOL get_uint_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2317 if (!ptr_param) return FALSE;
2319 if (!entry->hdr.loaded)
2321 WCHAR buf[32];
2322 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->uint.val = wcstol( buf, NULL, 10 );
2324 *(UINT *)ptr_param = entry->uint.val;
2325 return TRUE;
2328 /* set a uint parameter in the registry */
2329 static BOOL set_uint_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2331 WCHAR bufW[32];
2332 char buf[32];
2334 sprintf( buf, "%u", int_param );
2335 asciiz_to_unicode( bufW, buf );
2336 if (!save_entry_string( &entry->hdr, bufW, flags )) return FALSE;
2337 entry->uint.val = int_param;
2338 entry->hdr.loaded = TRUE;
2339 return TRUE;
2342 /* initialize a uint parameter */
2343 static BOOL init_uint_entry( union sysparam_all_entry *entry )
2345 WCHAR bufW[32];
2346 char buf[32];
2348 sprintf( buf, "%u", entry->uint.val );
2349 asciiz_to_unicode( bufW, buf );
2350 return init_entry_string( &entry->hdr, bufW );
2353 /* load a twips parameter from the registry */
2354 static BOOL get_twips_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2356 int val;
2358 if (!ptr_param) return FALSE;
2360 if (!entry->hdr.loaded)
2362 WCHAR buf[32];
2363 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->uint.val = wcstol( buf, NULL, 10 );
2366 /* Dimensions are quoted as being "twips" values if negative and pixels if positive.
2367 * One inch is 1440 twips.
2368 * See for example
2369 * Technical Reference to the Windows 2000 Registry ->
2370 * HKEY_CURRENT_USER -> Control Panel -> Desktop -> WindowMetrics
2372 val = entry->uint.val;
2373 if (val < 0)
2374 val = muldiv( -val, dpi, 1440 );
2375 else
2376 val = map_to_dpi( val, dpi );
2378 *(int *)ptr_param = val;
2379 return TRUE;
2382 /* set a twips parameter in the registry */
2383 static BOOL set_twips_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2385 int val = int_param;
2386 if (val > 0) val = map_from_system_dpi( val );
2387 return set_int_entry( entry, val, ptr_param, flags );
2390 /* load a bool parameter from the registry */
2391 static BOOL get_bool_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2393 if (!ptr_param) return FALSE;
2395 if (!entry->hdr.loaded)
2397 WCHAR buf[32];
2398 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->bool.val = wcstol( buf, NULL, 10 ) != 0;
2400 *(UINT *)ptr_param = entry->bool.val;
2401 return TRUE;
2404 /* set a bool parameter in the registry */
2405 static BOOL set_bool_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2407 WCHAR buf[] = { int_param ? '1' : '0', 0 };
2409 if (!save_entry_string( &entry->hdr, buf, flags )) return FALSE;
2410 entry->bool.val = int_param != 0;
2411 entry->hdr.loaded = TRUE;
2412 return TRUE;
2415 /* initialize a bool parameter */
2416 static BOOL init_bool_entry( union sysparam_all_entry *entry )
2418 WCHAR buf[] = { entry->bool.val ? '1' : '0', 0 };
2420 return init_entry_string( &entry->hdr, buf );
2423 /* load a bool parameter using Yes/No strings from the registry */
2424 static BOOL get_yesno_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2426 if (!ptr_param) return FALSE;
2428 if (!entry->hdr.loaded)
2430 WCHAR buf[32];
2431 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->bool.val = !wcsicmp( yesW, buf );
2433 *(UINT *)ptr_param = entry->bool.val;
2434 return TRUE;
2437 /* set a bool parameter using Yes/No strings from the registry */
2438 static BOOL set_yesno_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2440 const WCHAR *str = int_param ? yesW : noW;
2442 if (!save_entry_string( &entry->hdr, str, flags )) return FALSE;
2443 entry->bool.val = int_param != 0;
2444 entry->hdr.loaded = TRUE;
2445 return TRUE;
2448 /* initialize a bool parameter using Yes/No strings */
2449 static BOOL init_yesno_entry( union sysparam_all_entry *entry )
2451 return init_entry_string( &entry->hdr, entry->bool.val ? yesW : noW );
2454 /* load a dword (binary) parameter from the registry */
2455 static BOOL get_dword_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2457 if (!ptr_param) return FALSE;
2459 if (!entry->hdr.loaded)
2461 DWORD val;
2462 if (load_entry( &entry->hdr, &val, sizeof(val) ) == sizeof(DWORD)) entry->dword.val = val;
2464 *(DWORD *)ptr_param = entry->dword.val;
2465 return TRUE;
2468 /* set a dword (binary) parameter in the registry */
2469 static BOOL set_dword_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2471 DWORD val = PtrToUlong( ptr_param );
2473 if (!save_entry( &entry->hdr, &val, sizeof(val), REG_DWORD, flags )) return FALSE;
2474 entry->dword.val = val;
2475 entry->hdr.loaded = TRUE;
2476 return TRUE;
2479 /* initialize a dword parameter */
2480 static BOOL init_dword_entry( union sysparam_all_entry *entry )
2482 return init_entry( &entry->hdr, &entry->dword.val, sizeof(entry->dword.val), REG_DWORD );
2485 /* load an RGB parameter from the registry */
2486 static BOOL get_rgb_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2488 if (!ptr_param) return FALSE;
2490 if (!entry->hdr.loaded)
2492 WCHAR buf[32];
2494 if (load_entry( &entry->hdr, buf, sizeof(buf) ))
2496 DWORD r, g, b;
2497 WCHAR *end, *str = buf;
2499 r = wcstoul( str, &end, 10 );
2500 if (end == str || !*end) goto done;
2501 str = end + 1;
2502 g = wcstoul( str, &end, 10 );
2503 if (end == str || !*end) goto done;
2504 str = end + 1;
2505 b = wcstoul( str, &end, 10 );
2506 if (end == str) goto done;
2507 if (r > 255 || g > 255 || b > 255) goto done;
2508 entry->rgb.val = RGB( r, g, b );
2511 done:
2512 *(COLORREF *)ptr_param = entry->rgb.val;
2513 return TRUE;
2516 /* set an RGB parameter in the registry */
2517 static BOOL set_rgb_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2519 WCHAR bufW[32];
2520 char buf[32];
2521 HBRUSH brush;
2522 HPEN pen;
2524 sprintf( buf, "%u %u %u", GetRValue(int_param), GetGValue(int_param), GetBValue(int_param) );
2525 asciiz_to_unicode( bufW, buf );
2526 if (!save_entry_string( &entry->hdr, bufW, flags )) return FALSE;
2527 entry->rgb.val = int_param;
2528 entry->hdr.loaded = TRUE;
2529 if ((brush = InterlockedExchangePointer( (void **)&entry->rgb.brush, 0 )))
2531 make_gdi_object_system( brush, FALSE );
2532 NtGdiDeleteObjectApp( brush );
2534 if ((pen = InterlockedExchangePointer( (void **)&entry->rgb.pen, 0 )))
2536 make_gdi_object_system( pen, FALSE );
2537 NtGdiDeleteObjectApp( pen );
2539 return TRUE;
2542 /* initialize an RGB parameter */
2543 static BOOL init_rgb_entry( union sysparam_all_entry *entry )
2545 WCHAR bufW[32];
2546 char buf[32];
2548 sprintf( buf, "%u %u %u", GetRValue(entry->rgb.val), GetGValue(entry->rgb.val),
2549 GetBValue(entry->rgb.val) );
2550 asciiz_to_unicode( bufW, buf );
2551 return init_entry_string( &entry->hdr, bufW );
2554 /* get a path parameter in the registry */
2555 static BOOL get_path_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2557 if (!ptr_param) return FALSE;
2559 if (!entry->hdr.loaded)
2561 WCHAR buffer[MAX_PATH];
2563 if (load_entry( &entry->hdr, buffer, sizeof(buffer) ))
2564 lstrcpynW( entry->path.path, buffer, MAX_PATH );
2566 lstrcpynW( ptr_param, entry->path.path, int_param );
2567 return TRUE;
2570 /* set a path parameter in the registry */
2571 static BOOL set_path_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2573 WCHAR buffer[MAX_PATH];
2574 BOOL ret;
2576 lstrcpynW( buffer, ptr_param, MAX_PATH );
2577 ret = save_entry_string( &entry->hdr, buffer, flags );
2578 if (ret)
2580 lstrcpyW( entry->path.path, buffer );
2581 entry->hdr.loaded = TRUE;
2583 return ret;
2586 /* initialize a path parameter */
2587 static BOOL init_path_entry( union sysparam_all_entry *entry )
2589 return init_entry_string( &entry->hdr, entry->path.path );
2592 /* get a binary parameter in the registry */
2593 static BOOL get_binary_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2595 if (!ptr_param) return FALSE;
2597 if (!entry->hdr.loaded)
2599 void *buffer = malloc( entry->bin.size );
2600 DWORD len = load_entry( &entry->hdr, buffer, entry->bin.size );
2602 if (len)
2604 memcpy( entry->bin.ptr, buffer, entry->bin.size );
2605 memset( (char *)entry->bin.ptr + len, 0, entry->bin.size - len );
2607 free( buffer );
2609 memcpy( ptr_param, entry->bin.ptr, min( int_param, entry->bin.size ) );
2610 return TRUE;
2613 /* set a binary parameter in the registry */
2614 static BOOL set_binary_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2616 BOOL ret;
2617 void *buffer = malloc( entry->bin.size );
2619 memcpy( buffer, entry->bin.ptr, entry->bin.size );
2620 memcpy( buffer, ptr_param, min( int_param, entry->bin.size ));
2621 ret = save_entry( &entry->hdr, buffer, entry->bin.size, REG_BINARY, flags );
2622 if (ret)
2624 memcpy( entry->bin.ptr, buffer, entry->bin.size );
2625 entry->hdr.loaded = TRUE;
2627 free( buffer );
2628 return ret;
2631 /* initialize a binary parameter */
2632 static BOOL init_binary_entry( union sysparam_all_entry *entry )
2634 return init_entry( &entry->hdr, entry->bin.ptr, entry->bin.size, REG_BINARY );
2637 static void logfont16to32( const LOGFONT16 *font16, LPLOGFONTW font32 )
2639 font32->lfHeight = font16->lfHeight;
2640 font32->lfWidth = font16->lfWidth;
2641 font32->lfEscapement = font16->lfEscapement;
2642 font32->lfOrientation = font16->lfOrientation;
2643 font32->lfWeight = font16->lfWeight;
2644 font32->lfItalic = font16->lfItalic;
2645 font32->lfUnderline = font16->lfUnderline;
2646 font32->lfStrikeOut = font16->lfStrikeOut;
2647 font32->lfCharSet = font16->lfCharSet;
2648 font32->lfOutPrecision = font16->lfOutPrecision;
2649 font32->lfClipPrecision = font16->lfClipPrecision;
2650 font32->lfQuality = font16->lfQuality;
2651 font32->lfPitchAndFamily = font16->lfPitchAndFamily;
2652 win32u_mbtowc( NULL, font32->lfFaceName, LF_FACESIZE, font16->lfFaceName,
2653 strlen( font16->lfFaceName ));
2654 font32->lfFaceName[LF_FACESIZE-1] = 0;
2657 static void get_real_fontname( LOGFONTW *lf, WCHAR fullname[LF_FACESIZE] )
2659 struct font_enum_entry enum_entry;
2660 ULONG count = sizeof(enum_entry);
2661 HDC hdc;
2663 hdc = get_display_dc();
2664 NtGdiEnumFonts( hdc, 0, 0, lstrlenW( lf->lfFaceName ), lf->lfFaceName, lf->lfCharSet,
2665 &count, &enum_entry );
2666 release_display_dc( hdc );
2668 if (count)
2669 lstrcpyW( fullname, enum_entry.lf.elfFullName );
2670 else
2671 lstrcpyW( fullname, lf->lfFaceName );
2674 /* get text metrics and/or "average" char width of the specified logfont
2675 * for the specified dc */
2676 static void get_text_metr_size( HDC hdc, LOGFONTW *plf, TEXTMETRICW * ptm, UINT *psz)
2678 ENUMLOGFONTEXDVW exdv = { .elfEnumLogfontEx.elfLogFont = *plf };
2679 HFONT hfont, hfontsav;
2680 TEXTMETRICW tm;
2681 if (!ptm) ptm = &tm;
2682 hfont = NtGdiHfontCreate( &exdv, sizeof(exdv), 0, 0, NULL );
2683 if (!hfont || !(hfontsav = NtGdiSelectFont( hdc, hfont )))
2685 ptm->tmHeight = -1;
2686 if (psz) *psz = 10;
2687 if (hfont) NtGdiDeleteObjectApp( hfont );
2688 return;
2690 NtGdiGetTextMetricsW( hdc, ptm, 0 );
2691 if (psz)
2693 SIZE sz;
2694 static const WCHAR abcdW[] =
2695 {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
2696 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
2697 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
2698 if (NtGdiGetTextExtentExW( hdc, abcdW, ARRAYSIZE(abcdW), 0, NULL, NULL, &sz, 0 ))
2699 *psz = (sz.cx / 26 + 1) / 2;
2700 else *psz = 10;
2702 NtGdiSelectFont( hdc, hfontsav );
2703 NtGdiDeleteObjectApp( hfont );
2706 /* adjust some of the raw values found in the registry */
2707 static void normalize_nonclientmetrics( NONCLIENTMETRICSW *pncm)
2709 TEXTMETRICW tm;
2710 HDC hdc = get_display_dc();
2712 if( pncm->iBorderWidth < 1) pncm->iBorderWidth = 1;
2713 if( pncm->iCaptionWidth < 8) pncm->iCaptionWidth = 8;
2714 if( pncm->iScrollWidth < 8) pncm->iScrollWidth = 8;
2715 if( pncm->iScrollHeight < 8) pncm->iScrollHeight = 8;
2717 /* adjust some heights to the corresponding font */
2718 get_text_metr_size( hdc, &pncm->lfMenuFont, &tm, NULL);
2719 pncm->iMenuHeight = max( pncm->iMenuHeight, 2 + tm.tmHeight + tm.tmExternalLeading );
2720 get_text_metr_size( hdc, &pncm->lfCaptionFont, &tm, NULL);
2721 pncm->iCaptionHeight = max( pncm->iCaptionHeight, 2 + tm.tmHeight);
2722 get_text_metr_size( hdc, &pncm->lfSmCaptionFont, &tm, NULL);
2723 pncm->iSmCaptionHeight = max( pncm->iSmCaptionHeight, 2 + tm.tmHeight);
2724 release_display_dc( hdc );
2727 /* load a font (binary) parameter from the registry */
2728 static BOOL get_font_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2730 LOGFONTW font;
2732 if (!ptr_param) return FALSE;
2734 if (!entry->hdr.loaded)
2736 switch (load_entry( &entry->hdr, &font, sizeof(font) ))
2738 case sizeof(font):
2739 if (font.lfHeight > 0) /* positive height value means points ( inch/72 ) */
2740 font.lfHeight = -muldiv( font.lfHeight, USER_DEFAULT_SCREEN_DPI, 72 );
2741 entry->font.val = font;
2742 break;
2743 case sizeof(LOGFONT16): /* win9x-winME format */
2744 logfont16to32( (LOGFONT16 *)&font, &entry->font.val );
2745 if (entry->font.val.lfHeight > 0)
2746 entry->font.val.lfHeight = -muldiv( entry->font.val.lfHeight, USER_DEFAULT_SCREEN_DPI, 72 );
2747 break;
2748 default:
2749 WARN( "Unknown format in key %s value %s\n",
2750 debugstr_a( parameter_key_names[entry->hdr.base_key] ),
2751 debugstr_a( entry->hdr.regval ));
2752 /* fall through */
2753 case 0: /* use the default GUI font */
2754 NtGdiExtGetObjectW( get_stock_object( DEFAULT_GUI_FONT ), sizeof(font), &font );
2755 font.lfHeight = map_from_system_dpi( font.lfHeight );
2756 font.lfWeight = entry->font.weight;
2757 entry->font.val = font;
2758 break;
2760 get_real_fontname( &entry->font.val, entry->font.fullname );
2761 entry->hdr.loaded = TRUE;
2763 font = entry->font.val;
2764 font.lfHeight = map_to_dpi( font.lfHeight, dpi );
2765 lstrcpyW( font.lfFaceName, entry->font.fullname );
2766 *(LOGFONTW *)ptr_param = font;
2767 return TRUE;
2770 /* set a font (binary) parameter in the registry */
2771 static BOOL set_font_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2773 LOGFONTW font;
2774 WCHAR *ptr;
2776 memcpy( &font, ptr_param, sizeof(font) );
2777 /* zero pad the end of lfFaceName so we don't save uninitialised data */
2778 for (ptr = font.lfFaceName; ptr < font.lfFaceName + LF_FACESIZE && *ptr; ptr++);
2779 if (ptr < font.lfFaceName + LF_FACESIZE)
2780 memset( ptr, 0, (font.lfFaceName + LF_FACESIZE - ptr) * sizeof(WCHAR) );
2781 if (font.lfHeight < 0) font.lfHeight = map_from_system_dpi( font.lfHeight );
2783 if (!save_entry( &entry->hdr, &font, sizeof(font), REG_BINARY, flags )) return FALSE;
2784 entry->font.val = font;
2785 get_real_fontname( &entry->font.val, entry->font.fullname );
2786 entry->hdr.loaded = TRUE;
2787 return TRUE;
2790 /* initialize a font (binary) parameter */
2791 static BOOL init_font_entry( union sysparam_all_entry *entry )
2793 NtGdiExtGetObjectW( get_stock_object( DEFAULT_GUI_FONT ), sizeof(entry->font.val), &entry->font.val );
2794 entry->font.val.lfHeight = map_from_system_dpi( entry->font.val.lfHeight );
2795 entry->font.val.lfWeight = entry->font.weight;
2796 get_real_fontname( &entry->font.val, entry->font.fullname );
2797 return init_entry( &entry->hdr, &entry->font.val, sizeof(entry->font.val), REG_BINARY );
2800 /* get a user pref parameter in the registry */
2801 static BOOL get_userpref_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2803 union sysparam_all_entry *parent_entry = (union sysparam_all_entry *)entry->pref.parent;
2804 BYTE prefs[8];
2806 if (!ptr_param) return FALSE;
2808 if (!parent_entry->hdr.get( parent_entry, sizeof(prefs), prefs, dpi )) return FALSE;
2809 *(BOOL *)ptr_param = (prefs[entry->pref.offset] & entry->pref.mask) != 0;
2810 return TRUE;
2813 /* set a user pref parameter in the registry */
2814 static BOOL set_userpref_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2816 union sysparam_all_entry *parent_entry = (union sysparam_all_entry *)entry->pref.parent;
2817 BYTE prefs[8];
2819 parent_entry->hdr.loaded = FALSE; /* force loading it again */
2820 if (!parent_entry->hdr.get( parent_entry, sizeof(prefs), prefs, get_system_dpi() )) return FALSE;
2822 if (PtrToUlong( ptr_param )) prefs[entry->pref.offset] |= entry->pref.mask;
2823 else prefs[entry->pref.offset] &= ~entry->pref.mask;
2825 return parent_entry->hdr.set( parent_entry, sizeof(prefs), prefs, flags );
2828 static BOOL get_entry_dpi( void *ptr, UINT int_param, void *ptr_param, UINT dpi )
2830 union sysparam_all_entry *entry = ptr;
2831 return entry->hdr.get( entry, int_param, ptr_param, dpi );
2834 static BOOL get_entry( void *ptr, UINT int_param, void *ptr_param )
2836 return get_entry_dpi( ptr, int_param, ptr_param, get_system_dpi() );
2839 static BOOL set_entry( void *ptr, UINT int_param, void *ptr_param, UINT flags )
2841 union sysparam_all_entry *entry = ptr;
2842 return entry->hdr.set( entry, int_param, ptr_param, flags );
2845 #define UINT_ENTRY(name,val,base,reg) \
2846 struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_uint_entry, init_uint_entry, \
2847 base, reg }, (val) }
2849 #define UINT_ENTRY_MIRROR(name,val,base,reg,mirror_base) \
2850 struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_uint_entry, init_uint_entry, \
2851 base, reg, mirror_base, reg }, (val) }
2853 #define INT_ENTRY(name,val,base,reg) \
2854 struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_int_entry, init_int_entry, \
2855 base, reg }, (val) }
2857 #define BOOL_ENTRY(name,val,base,reg) \
2858 struct sysparam_bool_entry entry_##name = { { get_bool_entry, set_bool_entry, init_bool_entry, \
2859 base, reg }, (val) }
2861 #define BOOL_ENTRY_MIRROR(name,val,base,reg,mirror_base) \
2862 struct sysparam_bool_entry entry_##name = { { get_bool_entry, set_bool_entry, init_bool_entry, \
2863 base, reg, mirror_base, reg }, (val) }
2865 #define TWIPS_ENTRY(name,val,base,reg) \
2866 struct sysparam_uint_entry entry_##name = { { get_twips_entry, set_twips_entry, init_int_entry, \
2867 base, reg }, (val) }
2869 #define YESNO_ENTRY(name,val,base,reg) \
2870 struct sysparam_bool_entry entry_##name = { { get_yesno_entry, set_yesno_entry, init_yesno_entry, \
2871 base, reg }, (val) }
2873 #define DWORD_ENTRY(name,val,base,reg) \
2874 struct sysparam_dword_entry entry_##name = { { get_dword_entry, set_dword_entry, init_dword_entry, \
2875 base, reg }, (val) }
2877 #define BINARY_ENTRY(name,data,base,reg) \
2878 struct sysparam_binary_entry entry_##name = { { get_binary_entry, set_binary_entry, init_binary_entry, \
2879 base, reg }, data, sizeof(data) }
2881 #define PATH_ENTRY(name,base,reg) \
2882 struct sysparam_path_entry entry_##name = { { get_path_entry, set_path_entry, init_path_entry, \
2883 base, reg } }
2885 #define FONT_ENTRY(name,weight,base,reg) \
2886 struct sysparam_font_entry entry_##name = { { get_font_entry, set_font_entry, init_font_entry, \
2887 base, reg }, (weight) }
2889 #define USERPREF_ENTRY(name,offset,mask) \
2890 struct sysparam_pref_entry entry_##name = { { get_userpref_entry, set_userpref_entry }, \
2891 &entry_USERPREFERENCESMASK, (offset), (mask) }
2893 static UINT_ENTRY( DRAGWIDTH, 4, DESKTOP_KEY, "DragWidth" );
2894 static UINT_ENTRY( DRAGHEIGHT, 4, DESKTOP_KEY, "DragHeight" );
2895 static UINT_ENTRY( DOUBLECLICKTIME, 500, MOUSE_KEY, "DoubleClickSpeed" );
2896 static UINT_ENTRY( FONTSMOOTHING, 2, DESKTOP_KEY, "FontSmoothing" );
2897 static UINT_ENTRY( GRIDGRANULARITY, 0, DESKTOP_KEY, "GridGranularity" );
2898 static UINT_ENTRY( KEYBOARDDELAY, 1, KEYBOARD_KEY, "KeyboardDelay" );
2899 static UINT_ENTRY( KEYBOARDSPEED, 31, KEYBOARD_KEY, "KeyboardSpeed" );
2900 static UINT_ENTRY( MENUSHOWDELAY, 400, DESKTOP_KEY, "MenuShowDelay" );
2901 static UINT_ENTRY( MINARRANGE, ARW_HIDE, METRICS_KEY, "MinArrange" );
2902 static UINT_ENTRY( MINHORZGAP, 0, METRICS_KEY, "MinHorzGap" );
2903 static UINT_ENTRY( MINVERTGAP, 0, METRICS_KEY, "MinVertGap" );
2904 static UINT_ENTRY( MINWIDTH, 154, METRICS_KEY, "MinWidth" );
2905 static UINT_ENTRY( MOUSEHOVERHEIGHT, 4, MOUSE_KEY, "MouseHoverHeight" );
2906 static UINT_ENTRY( MOUSEHOVERTIME, 400, MOUSE_KEY, "MouseHoverTime" );
2907 static UINT_ENTRY( MOUSEHOVERWIDTH, 4, MOUSE_KEY, "MouseHoverWidth" );
2908 static UINT_ENTRY( MOUSESPEED, 10, MOUSE_KEY, "MouseSensitivity" );
2909 static UINT_ENTRY( MOUSETRAILS, 0, MOUSE_KEY, "MouseTrails" );
2910 static UINT_ENTRY( SCREENSAVETIMEOUT, 300, DESKTOP_KEY, "ScreenSaveTimeOut" );
2911 static UINT_ENTRY( WHEELSCROLLCHARS, 3, DESKTOP_KEY, "WheelScrollChars" );
2912 static UINT_ENTRY( WHEELSCROLLLINES, 3, DESKTOP_KEY, "WheelScrollLines" );
2913 static UINT_ENTRY_MIRROR( DOUBLECLKHEIGHT, 4, MOUSE_KEY, "DoubleClickHeight", DESKTOP_KEY );
2914 static UINT_ENTRY_MIRROR( DOUBLECLKWIDTH, 4, MOUSE_KEY, "DoubleClickWidth", DESKTOP_KEY );
2915 static UINT_ENTRY_MIRROR( MENUDROPALIGNMENT, 0, DESKTOP_KEY, "MenuDropAlignment", VERSION_KEY );
2917 static INT_ENTRY( MOUSETHRESHOLD1, 6, MOUSE_KEY, "MouseThreshold1" );
2918 static INT_ENTRY( MOUSETHRESHOLD2, 10, MOUSE_KEY, "MouseThreshold2" );
2919 static INT_ENTRY( MOUSEACCELERATION, 1, MOUSE_KEY, "MouseSpeed" );
2921 static BOOL_ENTRY( BLOCKSENDINPUTRESETS, FALSE, DESKTOP_KEY, "BlockSendInputResets" );
2922 static BOOL_ENTRY( DRAGFULLWINDOWS, FALSE, DESKTOP_KEY, "DragFullWindows" );
2923 static BOOL_ENTRY( KEYBOARDPREF, TRUE, KEYBOARDPREF_KEY, "On" );
2924 static BOOL_ENTRY( LOWPOWERACTIVE, FALSE, DESKTOP_KEY, "LowPowerActive" );
2925 static BOOL_ENTRY( MOUSEBUTTONSWAP, FALSE, MOUSE_KEY, "SwapMouseButtons" );
2926 static BOOL_ENTRY( POWEROFFACTIVE, FALSE, DESKTOP_KEY, "PowerOffActive" );
2927 static BOOL_ENTRY( SCREENREADER, FALSE, SCREENREADER_KEY, "On" );
2928 static BOOL_ENTRY( SCREENSAVEACTIVE, TRUE, DESKTOP_KEY, "ScreenSaveActive" );
2929 static BOOL_ENTRY( SCREENSAVERRUNNING, FALSE, DESKTOP_KEY, "WINE_ScreenSaverRunning" ); /* FIXME - real value */
2930 static BOOL_ENTRY( SHOWSOUNDS, FALSE, SHOWSOUNDS_KEY, "On" );
2931 static BOOL_ENTRY( SNAPTODEFBUTTON, FALSE, MOUSE_KEY, "SnapToDefaultButton" );
2932 static BOOL_ENTRY_MIRROR( ICONTITLEWRAP, TRUE, DESKTOP_KEY, "IconTitleWrap", METRICS_KEY );
2933 static BOOL_ENTRY( AUDIODESC_ON, FALSE, AUDIODESC_KEY, "On" );
2935 static TWIPS_ENTRY( BORDER, -15, METRICS_KEY, "BorderWidth" );
2936 static TWIPS_ENTRY( CAPTIONHEIGHT, -270, METRICS_KEY, "CaptionHeight" );
2937 static TWIPS_ENTRY( CAPTIONWIDTH, -270, METRICS_KEY, "CaptionWidth" );
2938 static TWIPS_ENTRY( ICONHORIZONTALSPACING, -1125, METRICS_KEY, "IconSpacing" );
2939 static TWIPS_ENTRY( ICONVERTICALSPACING, -1125, METRICS_KEY, "IconVerticalSpacing" );
2940 static TWIPS_ENTRY( MENUHEIGHT, -270, METRICS_KEY, "MenuHeight" );
2941 static TWIPS_ENTRY( MENUWIDTH, -270, METRICS_KEY, "MenuWidth" );
2942 static TWIPS_ENTRY( PADDEDBORDERWIDTH, 0, METRICS_KEY, "PaddedBorderWidth" );
2943 static TWIPS_ENTRY( SCROLLHEIGHT, -240, METRICS_KEY, "ScrollHeight" );
2944 static TWIPS_ENTRY( SCROLLWIDTH, -240, METRICS_KEY, "ScrollWidth" );
2945 static TWIPS_ENTRY( SMCAPTIONHEIGHT, -225, METRICS_KEY, "SmCaptionHeight" );
2946 static TWIPS_ENTRY( SMCAPTIONWIDTH, -225, METRICS_KEY, "SmCaptionWidth" );
2948 static YESNO_ENTRY( BEEP, TRUE, SOUND_KEY, "Beep" );
2950 static DWORD_ENTRY( ACTIVEWINDOWTRACKING, 0, MOUSE_KEY, "ActiveWindowTracking" );
2951 static DWORD_ENTRY( ACTIVEWNDTRKTIMEOUT, 0, DESKTOP_KEY, "ActiveWndTrackTimeout" );
2952 static DWORD_ENTRY( CARETWIDTH, 1, DESKTOP_KEY, "CaretWidth" );
2953 static DWORD_ENTRY( DPISCALINGVER, 0, DESKTOP_KEY, "DpiScalingVer" );
2954 static DWORD_ENTRY( FOCUSBORDERHEIGHT, 1, DESKTOP_KEY, "FocusBorderHeight" );
2955 static DWORD_ENTRY( FOCUSBORDERWIDTH, 1, DESKTOP_KEY, "FocusBorderWidth" );
2956 static DWORD_ENTRY( FONTSMOOTHINGCONTRAST, 0, DESKTOP_KEY, "FontSmoothingGamma" );
2957 static DWORD_ENTRY( FONTSMOOTHINGORIENTATION, FE_FONTSMOOTHINGORIENTATIONRGB, DESKTOP_KEY, "FontSmoothingOrientation" );
2958 static DWORD_ENTRY( FONTSMOOTHINGTYPE, FE_FONTSMOOTHINGSTANDARD, DESKTOP_KEY, "FontSmoothingType" );
2959 static DWORD_ENTRY( FOREGROUNDFLASHCOUNT, 3, DESKTOP_KEY, "ForegroundFlashCount" );
2960 static DWORD_ENTRY( FOREGROUNDLOCKTIMEOUT, 0, DESKTOP_KEY, "ForegroundLockTimeout" );
2961 static DWORD_ENTRY( LOGPIXELS, 0, DESKTOP_KEY, "LogPixels" );
2962 static DWORD_ENTRY( MOUSECLICKLOCKTIME, 1200, DESKTOP_KEY, "ClickLockTime" );
2963 static DWORD_ENTRY( AUDIODESC_LOCALE, 0, AUDIODESC_KEY, "Locale" );
2965 static PATH_ENTRY( DESKPATTERN, DESKTOP_KEY, "Pattern" );
2966 static PATH_ENTRY( DESKWALLPAPER, DESKTOP_KEY, "Wallpaper" );
2968 static BYTE user_prefs[8] = { 0x30, 0x00, 0x00, 0x80, 0x12, 0x00, 0x00, 0x00 };
2969 static BINARY_ENTRY( USERPREFERENCESMASK, user_prefs, DESKTOP_KEY, "UserPreferencesMask" );
2971 static FONT_ENTRY( CAPTIONLOGFONT, FW_BOLD, METRICS_KEY, "CaptionFont" );
2972 static FONT_ENTRY( ICONTITLELOGFONT, FW_NORMAL, METRICS_KEY, "IconFont" );
2973 static FONT_ENTRY( MENULOGFONT, FW_NORMAL, METRICS_KEY, "MenuFont" );
2974 static FONT_ENTRY( MESSAGELOGFONT, FW_NORMAL, METRICS_KEY, "MessageFont" );
2975 static FONT_ENTRY( SMCAPTIONLOGFONT, FW_NORMAL, METRICS_KEY, "SmCaptionFont" );
2976 static FONT_ENTRY( STATUSLOGFONT, FW_NORMAL, METRICS_KEY, "StatusFont" );
2978 static USERPREF_ENTRY( MENUANIMATION, 0, 0x02 );
2979 static USERPREF_ENTRY( COMBOBOXANIMATION, 0, 0x04 );
2980 static USERPREF_ENTRY( LISTBOXSMOOTHSCROLLING, 0, 0x08 );
2981 static USERPREF_ENTRY( GRADIENTCAPTIONS, 0, 0x10 );
2982 static USERPREF_ENTRY( KEYBOARDCUES, 0, 0x20 );
2983 static USERPREF_ENTRY( ACTIVEWNDTRKZORDER, 0, 0x40 );
2984 static USERPREF_ENTRY( HOTTRACKING, 0, 0x80 );
2985 static USERPREF_ENTRY( MENUFADE, 1, 0x02 );
2986 static USERPREF_ENTRY( SELECTIONFADE, 1, 0x04 );
2987 static USERPREF_ENTRY( TOOLTIPANIMATION, 1, 0x08 );
2988 static USERPREF_ENTRY( TOOLTIPFADE, 1, 0x10 );
2989 static USERPREF_ENTRY( CURSORSHADOW, 1, 0x20 );
2990 static USERPREF_ENTRY( MOUSESONAR, 1, 0x40 );
2991 static USERPREF_ENTRY( MOUSECLICKLOCK, 1, 0x80 );
2992 static USERPREF_ENTRY( MOUSEVANISH, 2, 0x01 );
2993 static USERPREF_ENTRY( FLATMENU, 2, 0x02 );
2994 static USERPREF_ENTRY( DROPSHADOW, 2, 0x04 );
2995 static USERPREF_ENTRY( UIEFFECTS, 3, 0x80 );
2996 static USERPREF_ENTRY( DISABLEOVERLAPPEDCONTENT, 4, 0x01 );
2997 static USERPREF_ENTRY( CLIENTAREAANIMATION, 4, 0x02 );
2998 static USERPREF_ENTRY( CLEARTYPE, 4, 0x10 );
2999 static USERPREF_ENTRY( SPEECHRECOGNITION, 4, 0x20 );
3001 /* System parameter indexes */
3002 enum spi_index
3004 SPI_SETWORKAREA_IDX,
3005 SPI_INDEX_COUNT
3008 /* indicators whether system parameter value is loaded */
3009 static char spi_loaded[SPI_INDEX_COUNT];
3011 static struct sysparam_rgb_entry system_colors[] =
3013 #define RGB_ENTRY(name,val,reg) { { get_rgb_entry, set_rgb_entry, init_rgb_entry, COLORS_KEY, reg }, (val) }
3014 RGB_ENTRY( COLOR_SCROLLBAR, RGB(212, 208, 200), "Scrollbar" ),
3015 RGB_ENTRY( COLOR_BACKGROUND, RGB(58, 110, 165), "Background" ),
3016 RGB_ENTRY( COLOR_ACTIVECAPTION, RGB(10, 36, 106), "ActiveTitle" ),
3017 RGB_ENTRY( COLOR_INACTIVECAPTION, RGB(128, 128, 128), "InactiveTitle" ),
3018 RGB_ENTRY( COLOR_MENU, RGB(212, 208, 200), "Menu" ),
3019 RGB_ENTRY( COLOR_WINDOW, RGB(255, 255, 255), "Window" ),
3020 RGB_ENTRY( COLOR_WINDOWFRAME, RGB(0, 0, 0), "WindowFrame" ),
3021 RGB_ENTRY( COLOR_MENUTEXT, RGB(0, 0, 0), "MenuText" ),
3022 RGB_ENTRY( COLOR_WINDOWTEXT, RGB(0, 0, 0), "WindowText" ),
3023 RGB_ENTRY( COLOR_CAPTIONTEXT, RGB(255, 255, 255), "TitleText" ),
3024 RGB_ENTRY( COLOR_ACTIVEBORDER, RGB(212, 208, 200), "ActiveBorder" ),
3025 RGB_ENTRY( COLOR_INACTIVEBORDER, RGB(212, 208, 200), "InactiveBorder" ),
3026 RGB_ENTRY( COLOR_APPWORKSPACE, RGB(128, 128, 128), "AppWorkSpace" ),
3027 RGB_ENTRY( COLOR_HIGHLIGHT, RGB(10, 36, 106), "Hilight" ),
3028 RGB_ENTRY( COLOR_HIGHLIGHTTEXT, RGB(255, 255, 255), "HilightText" ),
3029 RGB_ENTRY( COLOR_BTNFACE, RGB(212, 208, 200), "ButtonFace" ),
3030 RGB_ENTRY( COLOR_BTNSHADOW, RGB(128, 128, 128), "ButtonShadow" ),
3031 RGB_ENTRY( COLOR_GRAYTEXT, RGB(128, 128, 128), "GrayText" ),
3032 RGB_ENTRY( COLOR_BTNTEXT, RGB(0, 0, 0), "ButtonText" ),
3033 RGB_ENTRY( COLOR_INACTIVECAPTIONTEXT, RGB(212, 208, 200), "InactiveTitleText" ),
3034 RGB_ENTRY( COLOR_BTNHIGHLIGHT, RGB(255, 255, 255), "ButtonHilight" ),
3035 RGB_ENTRY( COLOR_3DDKSHADOW, RGB(64, 64, 64), "ButtonDkShadow" ),
3036 RGB_ENTRY( COLOR_3DLIGHT, RGB(212, 208, 200), "ButtonLight" ),
3037 RGB_ENTRY( COLOR_INFOTEXT, RGB(0, 0, 0), "InfoText" ),
3038 RGB_ENTRY( COLOR_INFOBK, RGB(255, 255, 225), "InfoWindow" ),
3039 RGB_ENTRY( COLOR_ALTERNATEBTNFACE, RGB(181, 181, 181), "ButtonAlternateFace" ),
3040 RGB_ENTRY( COLOR_HOTLIGHT, RGB(0, 0, 200), "HotTrackingColor" ),
3041 RGB_ENTRY( COLOR_GRADIENTACTIVECAPTION, RGB(166, 202, 240), "GradientActiveTitle" ),
3042 RGB_ENTRY( COLOR_GRADIENTINACTIVECAPTION, RGB(192, 192, 192), "GradientInactiveTitle" ),
3043 RGB_ENTRY( COLOR_MENUHILIGHT, RGB(10, 36, 106), "MenuHilight" ),
3044 RGB_ENTRY( COLOR_MENUBAR, RGB(212, 208, 200), "MenuBar" )
3045 #undef RGB_ENTRY
3048 /* entries that are initialized by default in the registry */
3049 static union sysparam_all_entry * const default_entries[] =
3051 (union sysparam_all_entry *)&entry_ACTIVEWINDOWTRACKING,
3052 (union sysparam_all_entry *)&entry_ACTIVEWNDTRKTIMEOUT,
3053 (union sysparam_all_entry *)&entry_BEEP,
3054 (union sysparam_all_entry *)&entry_BLOCKSENDINPUTRESETS,
3055 (union sysparam_all_entry *)&entry_BORDER,
3056 (union sysparam_all_entry *)&entry_CAPTIONHEIGHT,
3057 (union sysparam_all_entry *)&entry_CAPTIONWIDTH,
3058 (union sysparam_all_entry *)&entry_CARETWIDTH,
3059 (union sysparam_all_entry *)&entry_DESKWALLPAPER,
3060 (union sysparam_all_entry *)&entry_DOUBLECLICKTIME,
3061 (union sysparam_all_entry *)&entry_DOUBLECLKHEIGHT,
3062 (union sysparam_all_entry *)&entry_DOUBLECLKWIDTH,
3063 (union sysparam_all_entry *)&entry_DRAGFULLWINDOWS,
3064 (union sysparam_all_entry *)&entry_DRAGHEIGHT,
3065 (union sysparam_all_entry *)&entry_DRAGWIDTH,
3066 (union sysparam_all_entry *)&entry_FOCUSBORDERHEIGHT,
3067 (union sysparam_all_entry *)&entry_FOCUSBORDERWIDTH,
3068 (union sysparam_all_entry *)&entry_FONTSMOOTHING,
3069 (union sysparam_all_entry *)&entry_FONTSMOOTHINGCONTRAST,
3070 (union sysparam_all_entry *)&entry_FONTSMOOTHINGORIENTATION,
3071 (union sysparam_all_entry *)&entry_FONTSMOOTHINGTYPE,
3072 (union sysparam_all_entry *)&entry_FOREGROUNDFLASHCOUNT,
3073 (union sysparam_all_entry *)&entry_FOREGROUNDLOCKTIMEOUT,
3074 (union sysparam_all_entry *)&entry_ICONHORIZONTALSPACING,
3075 (union sysparam_all_entry *)&entry_ICONTITLEWRAP,
3076 (union sysparam_all_entry *)&entry_ICONVERTICALSPACING,
3077 (union sysparam_all_entry *)&entry_KEYBOARDDELAY,
3078 (union sysparam_all_entry *)&entry_KEYBOARDPREF,
3079 (union sysparam_all_entry *)&entry_KEYBOARDSPEED,
3080 (union sysparam_all_entry *)&entry_LOWPOWERACTIVE,
3081 (union sysparam_all_entry *)&entry_MENUHEIGHT,
3082 (union sysparam_all_entry *)&entry_MENUSHOWDELAY,
3083 (union sysparam_all_entry *)&entry_MENUWIDTH,
3084 (union sysparam_all_entry *)&entry_MOUSEACCELERATION,
3085 (union sysparam_all_entry *)&entry_MOUSEBUTTONSWAP,
3086 (union sysparam_all_entry *)&entry_MOUSECLICKLOCKTIME,
3087 (union sysparam_all_entry *)&entry_MOUSEHOVERHEIGHT,
3088 (union sysparam_all_entry *)&entry_MOUSEHOVERTIME,
3089 (union sysparam_all_entry *)&entry_MOUSEHOVERWIDTH,
3090 (union sysparam_all_entry *)&entry_MOUSESPEED,
3091 (union sysparam_all_entry *)&entry_MOUSETHRESHOLD1,
3092 (union sysparam_all_entry *)&entry_MOUSETHRESHOLD2,
3093 (union sysparam_all_entry *)&entry_PADDEDBORDERWIDTH,
3094 (union sysparam_all_entry *)&entry_SCREENREADER,
3095 (union sysparam_all_entry *)&entry_SCROLLHEIGHT,
3096 (union sysparam_all_entry *)&entry_SCROLLWIDTH,
3097 (union sysparam_all_entry *)&entry_SHOWSOUNDS,
3098 (union sysparam_all_entry *)&entry_SMCAPTIONHEIGHT,
3099 (union sysparam_all_entry *)&entry_SMCAPTIONWIDTH,
3100 (union sysparam_all_entry *)&entry_SNAPTODEFBUTTON,
3101 (union sysparam_all_entry *)&entry_USERPREFERENCESMASK,
3102 (union sysparam_all_entry *)&entry_WHEELSCROLLCHARS,
3103 (union sysparam_all_entry *)&entry_WHEELSCROLLLINES,
3104 (union sysparam_all_entry *)&entry_AUDIODESC_LOCALE,
3105 (union sysparam_all_entry *)&entry_AUDIODESC_ON,
3108 void sysparams_init(void)
3111 DWORD i, dispos, dpi_scaling;
3112 WCHAR layout[KL_NAMELENGTH];
3113 pthread_mutexattr_t attr;
3114 HKEY hkey;
3116 static const WCHAR software_wineW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e'};
3117 static const WCHAR temporary_system_parametersW[] =
3118 {'T','e','m','p','o','r','a','r','y',' ','S','y','s','t','e','m',' ',
3119 'P','a','r','a','m','e','t','e','r','s'};
3120 static const WCHAR oneW[] = {'1',0};
3121 static const WCHAR kl_preloadW[] =
3122 {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d'};
3124 pthread_mutexattr_init( &attr );
3125 pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
3126 pthread_mutex_init( &user_mutex, &attr );
3127 pthread_mutexattr_destroy( &attr );
3129 if ((hkey = reg_create_key( hkcu_key, kl_preloadW, sizeof(kl_preloadW), 0, NULL )))
3131 if (NtUserGetKeyboardLayoutName( layout ))
3132 set_reg_value( hkey, oneW, REG_SZ, (const BYTE *)layout,
3133 (lstrlenW(layout) + 1) * sizeof(WCHAR) );
3134 NtClose( hkey );
3137 /* this one must be non-volatile */
3138 if (!(hkey = reg_create_key( hkcu_key, software_wineW, sizeof(software_wineW), 0, NULL )))
3140 ERR("Can't create wine registry branch\n");
3141 return;
3144 /* @@ Wine registry key: HKCU\Software\Wine\Temporary System Parameters */
3145 if (!(volatile_base_key = reg_create_key( hkey, temporary_system_parametersW,
3146 sizeof(temporary_system_parametersW),
3147 REG_OPTION_VOLATILE, &dispos )))
3148 ERR("Can't create non-permanent wine registry branch\n");
3150 NtClose( hkey );
3152 config_key = reg_create_key( NULL, config_keyW, sizeof(config_keyW), 0, NULL );
3154 get_dword_entry( (union sysparam_all_entry *)&entry_LOGPIXELS, 0, &system_dpi, 0 );
3155 if (!system_dpi) /* check fallback key */
3157 static const WCHAR log_pixelsW[] = {'L','o','g','P','i','x','e','l','s',0};
3158 static const WCHAR software_fontsW[] =
3159 {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s'};
3161 if ((hkey = reg_open_key( config_key, software_fontsW, sizeof(software_fontsW) )))
3163 char buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD)];
3164 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
3166 if (query_reg_value( hkey, log_pixelsW, value, sizeof(buffer) ) && value->Type == REG_DWORD)
3167 system_dpi = *(const DWORD *)value->Data;
3168 NtClose( hkey );
3171 if (!system_dpi) system_dpi = USER_DEFAULT_SCREEN_DPI;
3173 /* FIXME: what do the DpiScalingVer flags mean? */
3174 get_dword_entry( (union sysparam_all_entry *)&entry_DPISCALINGVER, 0, &dpi_scaling, 0 );
3175 if (!dpi_scaling) NtUserSetProcessDpiAwarenessContext( NTUSER_DPI_PER_MONITOR_AWARE, 0 );
3177 if (volatile_base_key && dispos == REG_CREATED_NEW_KEY) /* first process, initialize entries */
3179 for (i = 0; i < ARRAY_SIZE( default_entries ); i++)
3180 default_entries[i]->hdr.init( default_entries[i] );
3184 static BOOL update_desktop_wallpaper(void)
3186 /* FIXME: move implementation from user32 */
3187 entry_DESKWALLPAPER.hdr.loaded = entry_DESKPATTERN.hdr.loaded = FALSE;
3188 return TRUE;
3191 /***********************************************************************
3192 * NtUserSystemParametersInfoForDpi (win32u.@)
3194 BOOL WINAPI NtUserSystemParametersInfoForDpi( UINT action, UINT val, PVOID ptr, UINT winini, UINT dpi )
3196 BOOL ret = FALSE;
3198 switch (action)
3200 case SPI_GETICONTITLELOGFONT:
3201 ret = get_entry_dpi( &entry_ICONTITLELOGFONT, val, ptr, dpi );
3202 break;
3203 case SPI_GETNONCLIENTMETRICS:
3205 NONCLIENTMETRICSW *ncm = ptr;
3207 if (!ncm) break;
3208 ret = get_entry_dpi( &entry_BORDER, 0, &ncm->iBorderWidth, dpi ) &&
3209 get_entry_dpi( &entry_SCROLLWIDTH, 0, &ncm->iScrollWidth, dpi ) &&
3210 get_entry_dpi( &entry_SCROLLHEIGHT, 0, &ncm->iScrollHeight, dpi ) &&
3211 get_entry_dpi( &entry_CAPTIONWIDTH, 0, &ncm->iCaptionWidth, dpi ) &&
3212 get_entry_dpi( &entry_CAPTIONHEIGHT, 0, &ncm->iCaptionHeight, dpi ) &&
3213 get_entry_dpi( &entry_CAPTIONLOGFONT, 0, &ncm->lfCaptionFont, dpi ) &&
3214 get_entry_dpi( &entry_SMCAPTIONWIDTH, 0, &ncm->iSmCaptionWidth, dpi ) &&
3215 get_entry_dpi( &entry_SMCAPTIONHEIGHT, 0, &ncm->iSmCaptionHeight, dpi ) &&
3216 get_entry_dpi( &entry_SMCAPTIONLOGFONT, 0, &ncm->lfSmCaptionFont, dpi ) &&
3217 get_entry_dpi( &entry_MENUWIDTH, 0, &ncm->iMenuWidth, dpi ) &&
3218 get_entry_dpi( &entry_MENUHEIGHT, 0, &ncm->iMenuHeight, dpi ) &&
3219 get_entry_dpi( &entry_MENULOGFONT, 0, &ncm->lfMenuFont, dpi ) &&
3220 get_entry_dpi( &entry_STATUSLOGFONT, 0, &ncm->lfStatusFont, dpi ) &&
3221 get_entry_dpi( &entry_MESSAGELOGFONT, 0, &ncm->lfMessageFont, dpi );
3222 if (ret && ncm->cbSize == sizeof(NONCLIENTMETRICSW))
3223 ret = get_entry_dpi( &entry_PADDEDBORDERWIDTH, 0, &ncm->iPaddedBorderWidth, dpi );
3224 normalize_nonclientmetrics( ncm );
3225 break;
3227 case SPI_GETICONMETRICS:
3229 ICONMETRICSW *im = ptr;
3230 if (im && im->cbSize == sizeof(*im))
3231 ret = get_entry_dpi( &entry_ICONHORIZONTALSPACING, 0, &im->iHorzSpacing, dpi ) &&
3232 get_entry_dpi( &entry_ICONVERTICALSPACING, 0, &im->iVertSpacing, dpi ) &&
3233 get_entry_dpi( &entry_ICONTITLEWRAP, 0, &im->iTitleWrap, dpi ) &&
3234 get_entry_dpi( &entry_ICONTITLELOGFONT, 0, &im->lfFont, dpi );
3235 break;
3237 default:
3238 SetLastError( ERROR_INVALID_PARAMETER );
3239 break;
3241 return ret;
3244 /***********************************************************************
3245 * NtUserSystemParametersInfo (win32u.@)
3247 * Each system parameter has flag which shows whether the parameter
3248 * is loaded or not. Parameters, stored directly in SysParametersInfo are
3249 * loaded from registry only when they are requested and the flag is
3250 * "false", after the loading the flag is set to "true". On interprocess
3251 * notification of the parameter change the corresponding parameter flag is
3252 * set to "false". The parameter value will be reloaded when it is requested
3253 * the next time.
3254 * Parameters, backed by or depend on GetSystemMetrics are processed
3255 * differently. These parameters are always loaded. They are reloaded right
3256 * away on interprocess change notification. We can't do lazy loading because
3257 * we don't want to complicate GetSystemMetrics.
3258 * Parameters backed by driver settings are read from corresponding setting.
3259 * On the parameter change request the setting is changed. Interprocess change
3260 * notifications are ignored.
3261 * When parameter value is updated the changed value is stored in permanent
3262 * registry branch if saving is requested. Otherwise it is stored
3263 * in temporary branch
3265 * Some SPI values can also be stored as Twips values in the registry,
3266 * don't forget the conversion!
3268 BOOL WINAPI NtUserSystemParametersInfo( UINT action, UINT val, void *ptr, UINT winini )
3270 #define WINE_SPI_FIXME(x) \
3271 case x: \
3273 static BOOL warn = TRUE; \
3274 if (warn) \
3276 warn = FALSE; \
3277 FIXME( "Unimplemented action: %u (%s)\n", x, #x ); \
3280 SetLastError( ERROR_INVALID_SPI_VALUE ); \
3281 ret = FALSE; \
3282 break
3283 #define WINE_SPI_WARN(x) \
3284 case x: \
3285 WARN( "Ignored action: %u (%s)\n", x, #x ); \
3286 ret = TRUE; \
3287 break
3289 BOOL ret = user_driver->pSystemParametersInfo( action, val, ptr, winini );
3290 unsigned spi_idx = 0;
3292 if (!ret) switch (action)
3294 case SPI_GETBEEP:
3295 ret = get_entry( &entry_BEEP, val, ptr );
3296 break;
3297 case SPI_SETBEEP:
3298 ret = set_entry( &entry_BEEP, val, ptr, winini );
3299 break;
3300 case SPI_GETMOUSE:
3301 ret = get_entry( &entry_MOUSETHRESHOLD1, val, (INT *)ptr ) &&
3302 get_entry( &entry_MOUSETHRESHOLD2, val, (INT *)ptr + 1 ) &&
3303 get_entry( &entry_MOUSEACCELERATION, val, (INT *)ptr + 2 );
3304 break;
3305 case SPI_SETMOUSE:
3306 ret = set_entry( &entry_MOUSETHRESHOLD1, ((INT *)ptr)[0], ptr, winini ) &&
3307 set_entry( &entry_MOUSETHRESHOLD2, ((INT *)ptr)[1], ptr, winini ) &&
3308 set_entry( &entry_MOUSEACCELERATION, ((INT *)ptr)[2], ptr, winini );
3309 break;
3310 case SPI_GETBORDER:
3311 ret = get_entry( &entry_BORDER, val, ptr );
3312 if (*(INT*)ptr < 1) *(INT*)ptr = 1;
3313 break;
3314 case SPI_SETBORDER:
3315 ret = set_entry( &entry_BORDER, val, ptr, winini );
3316 break;
3317 case SPI_GETKEYBOARDSPEED:
3318 ret = get_entry( &entry_KEYBOARDSPEED, val, ptr );
3319 break;
3320 case SPI_SETKEYBOARDSPEED:
3321 if (val > 31) val = 31;
3322 ret = set_entry( &entry_KEYBOARDSPEED, val, ptr, winini );
3323 break;
3325 WINE_SPI_WARN(SPI_LANGDRIVER); /* not implemented in Windows */
3327 case SPI_ICONHORIZONTALSPACING:
3328 if (ptr != NULL)
3329 ret = get_entry( &entry_ICONHORIZONTALSPACING, val, ptr );
3330 else
3332 int min_val = map_to_dpi( 32, get_system_dpi() );
3333 ret = set_entry( &entry_ICONHORIZONTALSPACING, max( min_val, val ), ptr, winini );
3335 break;
3336 case SPI_GETSCREENSAVETIMEOUT:
3337 ret = get_entry( &entry_SCREENSAVETIMEOUT, val, ptr );
3338 break;
3339 case SPI_SETSCREENSAVETIMEOUT:
3340 ret = set_entry( &entry_SCREENSAVETIMEOUT, val, ptr, winini );
3341 break;
3342 case SPI_GETSCREENSAVEACTIVE:
3343 ret = get_entry( &entry_SCREENSAVEACTIVE, val, ptr );
3344 break;
3345 case SPI_SETSCREENSAVEACTIVE:
3346 ret = set_entry( &entry_SCREENSAVEACTIVE, val, ptr, winini );
3347 break;
3348 case SPI_GETGRIDGRANULARITY:
3349 ret = get_entry( &entry_GRIDGRANULARITY, val, ptr );
3350 break;
3351 case SPI_SETGRIDGRANULARITY:
3352 ret = set_entry( &entry_GRIDGRANULARITY, val, ptr, winini );
3353 break;
3354 case SPI_SETDESKWALLPAPER:
3355 if (!ptr || set_entry( &entry_DESKWALLPAPER, val, ptr, winini ))
3356 ret = update_desktop_wallpaper();
3357 break;
3358 case SPI_SETDESKPATTERN:
3359 if (!ptr || set_entry( &entry_DESKPATTERN, val, ptr, winini ))
3360 ret = update_desktop_wallpaper();
3361 break;
3362 case SPI_GETKEYBOARDDELAY:
3363 ret = get_entry( &entry_KEYBOARDDELAY, val, ptr );
3364 break;
3365 case SPI_SETKEYBOARDDELAY:
3366 ret = set_entry( &entry_KEYBOARDDELAY, val, ptr, winini );
3367 break;
3368 case SPI_ICONVERTICALSPACING:
3369 if (ptr != NULL)
3370 ret = get_entry( &entry_ICONVERTICALSPACING, val, ptr );
3371 else
3373 int min_val = map_to_dpi( 32, get_system_dpi() );
3374 ret = set_entry( &entry_ICONVERTICALSPACING, max( min_val, val ), ptr, winini );
3376 break;
3377 case SPI_GETICONTITLEWRAP:
3378 ret = get_entry( &entry_ICONTITLEWRAP, val, ptr );
3379 break;
3380 case SPI_SETICONTITLEWRAP:
3381 ret = set_entry( &entry_ICONTITLEWRAP, val, ptr, winini );
3382 break;
3383 case SPI_GETMENUDROPALIGNMENT:
3384 ret = get_entry( &entry_MENUDROPALIGNMENT, val, ptr );
3385 break;
3386 case SPI_SETMENUDROPALIGNMENT:
3387 ret = set_entry( &entry_MENUDROPALIGNMENT, val, ptr, winini );
3388 break;
3389 case SPI_SETDOUBLECLKWIDTH:
3390 ret = set_entry( &entry_DOUBLECLKWIDTH, val, ptr, winini );
3391 break;
3392 case SPI_SETDOUBLECLKHEIGHT:
3393 ret = set_entry( &entry_DOUBLECLKHEIGHT, val, ptr, winini );
3394 break;
3395 case SPI_GETICONTITLELOGFONT:
3396 ret = get_entry( &entry_ICONTITLELOGFONT, val, ptr );
3397 break;
3398 case SPI_SETDOUBLECLICKTIME:
3399 ret = set_entry( &entry_DOUBLECLICKTIME, val, ptr, winini );
3400 break;
3401 case SPI_SETMOUSEBUTTONSWAP:
3402 ret = set_entry( &entry_MOUSEBUTTONSWAP, val, ptr, winini );
3403 break;
3404 case SPI_SETICONTITLELOGFONT:
3405 ret = set_entry( &entry_ICONTITLELOGFONT, val, ptr, winini );
3406 break;
3407 case SPI_GETFASTTASKSWITCH:
3408 if (!ptr) return FALSE;
3409 *(BOOL *)ptr = TRUE;
3410 ret = TRUE;
3411 break;
3412 case SPI_SETFASTTASKSWITCH:
3413 /* the action is disabled */
3414 ret = FALSE;
3415 break;
3416 case SPI_SETDRAGFULLWINDOWS:
3417 ret = set_entry( &entry_DRAGFULLWINDOWS, val, ptr, winini );
3418 break;
3419 case SPI_GETDRAGFULLWINDOWS:
3420 ret = get_entry( &entry_DRAGFULLWINDOWS, val, ptr );
3421 break;
3422 case SPI_GETNONCLIENTMETRICS:
3424 NONCLIENTMETRICSW *nm = ptr;
3425 int padded_border;
3427 if (!ptr) return FALSE;
3429 ret = get_entry( &entry_BORDER, 0, &nm->iBorderWidth ) &&
3430 get_entry( &entry_PADDEDBORDERWIDTH, 0, &padded_border ) &&
3431 get_entry( &entry_SCROLLWIDTH, 0, &nm->iScrollWidth ) &&
3432 get_entry( &entry_SCROLLHEIGHT, 0, &nm->iScrollHeight ) &&
3433 get_entry( &entry_CAPTIONWIDTH, 0, &nm->iCaptionWidth ) &&
3434 get_entry( &entry_CAPTIONHEIGHT, 0, &nm->iCaptionHeight ) &&
3435 get_entry( &entry_CAPTIONLOGFONT, 0, &nm->lfCaptionFont ) &&
3436 get_entry( &entry_SMCAPTIONWIDTH, 0, &nm->iSmCaptionWidth ) &&
3437 get_entry( &entry_SMCAPTIONHEIGHT, 0, &nm->iSmCaptionHeight ) &&
3438 get_entry( &entry_SMCAPTIONLOGFONT, 0, &nm->lfSmCaptionFont ) &&
3439 get_entry( &entry_MENUWIDTH, 0, &nm->iMenuWidth ) &&
3440 get_entry( &entry_MENUHEIGHT, 0, &nm->iMenuHeight ) &&
3441 get_entry( &entry_MENULOGFONT, 0, &nm->lfMenuFont ) &&
3442 get_entry( &entry_STATUSLOGFONT, 0, &nm->lfStatusFont ) &&
3443 get_entry( &entry_MESSAGELOGFONT, 0, &nm->lfMessageFont );
3444 if (ret)
3446 nm->iBorderWidth += padded_border;
3447 if (nm->cbSize == sizeof(NONCLIENTMETRICSW)) nm->iPaddedBorderWidth = 0;
3449 normalize_nonclientmetrics( nm );
3450 break;
3452 case SPI_SETNONCLIENTMETRICS:
3454 LPNONCLIENTMETRICSW nm = ptr;
3455 int padded_border;
3457 if (nm && (nm->cbSize == sizeof(NONCLIENTMETRICSW) ||
3458 nm->cbSize == FIELD_OFFSET(NONCLIENTMETRICSW, iPaddedBorderWidth)))
3460 get_entry( &entry_PADDEDBORDERWIDTH, 0, &padded_border );
3462 ret = set_entry( &entry_BORDER, nm->iBorderWidth - padded_border, NULL, winini ) &&
3463 set_entry( &entry_SCROLLWIDTH, nm->iScrollWidth, NULL, winini ) &&
3464 set_entry( &entry_SCROLLHEIGHT, nm->iScrollHeight, NULL, winini ) &&
3465 set_entry( &entry_CAPTIONWIDTH, nm->iCaptionWidth, NULL, winini ) &&
3466 set_entry( &entry_CAPTIONHEIGHT, nm->iCaptionHeight, NULL, winini ) &&
3467 set_entry( &entry_SMCAPTIONWIDTH, nm->iSmCaptionWidth, NULL, winini ) &&
3468 set_entry( &entry_SMCAPTIONHEIGHT, nm->iSmCaptionHeight, NULL, winini ) &&
3469 set_entry( &entry_MENUWIDTH, nm->iMenuWidth, NULL, winini ) &&
3470 set_entry( &entry_MENUHEIGHT, nm->iMenuHeight, NULL, winini ) &&
3471 set_entry( &entry_MENULOGFONT, 0, &nm->lfMenuFont, winini ) &&
3472 set_entry( &entry_CAPTIONLOGFONT, 0, &nm->lfCaptionFont, winini ) &&
3473 set_entry( &entry_SMCAPTIONLOGFONT, 0, &nm->lfSmCaptionFont, winini ) &&
3474 set_entry( &entry_STATUSLOGFONT, 0, &nm->lfStatusFont, winini ) &&
3475 set_entry( &entry_MESSAGELOGFONT, 0, &nm->lfMessageFont, winini );
3477 break;
3479 case SPI_GETMINIMIZEDMETRICS:
3481 MINIMIZEDMETRICS *mm = ptr;
3482 if (mm && mm->cbSize == sizeof(*mm)) {
3483 ret = get_entry( &entry_MINWIDTH, 0, &mm->iWidth ) &&
3484 get_entry( &entry_MINHORZGAP, 0, &mm->iHorzGap ) &&
3485 get_entry( &entry_MINVERTGAP, 0, &mm->iVertGap ) &&
3486 get_entry( &entry_MINARRANGE, 0, &mm->iArrange );
3487 mm->iWidth = max( 0, mm->iWidth );
3488 mm->iHorzGap = max( 0, mm->iHorzGap );
3489 mm->iVertGap = max( 0, mm->iVertGap );
3490 mm->iArrange &= 0x0f;
3492 break;
3494 case SPI_SETMINIMIZEDMETRICS:
3496 MINIMIZEDMETRICS *mm = ptr;
3497 if (mm && mm->cbSize == sizeof(*mm))
3498 ret = set_entry( &entry_MINWIDTH, max( 0, mm->iWidth ), NULL, winini ) &&
3499 set_entry( &entry_MINHORZGAP, max( 0, mm->iHorzGap ), NULL, winini ) &&
3500 set_entry( &entry_MINVERTGAP, max( 0, mm->iVertGap ), NULL, winini ) &&
3501 set_entry( &entry_MINARRANGE, mm->iArrange & 0x0f, NULL, winini );
3502 break;
3504 case SPI_GETICONMETRICS:
3506 ICONMETRICSW *icon = ptr;
3507 if(icon && icon->cbSize == sizeof(*icon))
3509 ret = get_entry( &entry_ICONHORIZONTALSPACING, 0, &icon->iHorzSpacing ) &&
3510 get_entry( &entry_ICONVERTICALSPACING, 0, &icon->iVertSpacing ) &&
3511 get_entry( &entry_ICONTITLEWRAP, 0, &icon->iTitleWrap ) &&
3512 get_entry( &entry_ICONTITLELOGFONT, 0, &icon->lfFont );
3514 break;
3516 case SPI_SETICONMETRICS:
3518 ICONMETRICSW *icon = ptr;
3519 if (icon && icon->cbSize == sizeof(*icon))
3520 ret = set_entry( &entry_ICONVERTICALSPACING, max(32,icon->iVertSpacing), NULL, winini ) &&
3521 set_entry( &entry_ICONHORIZONTALSPACING, max(32,icon->iHorzSpacing), NULL, winini ) &&
3522 set_entry( &entry_ICONTITLEWRAP, icon->iTitleWrap, NULL, winini ) &&
3523 set_entry( &entry_ICONTITLELOGFONT, 0, &icon->lfFont, winini );
3524 break;
3526 case SPI_SETWORKAREA:
3528 if (!ptr) return FALSE;
3529 spi_idx = SPI_SETWORKAREA_IDX;
3530 work_area = *(RECT*)ptr;
3531 spi_loaded[spi_idx] = TRUE;
3532 ret = TRUE;
3533 break;
3535 case SPI_GETWORKAREA:
3537 if (!ptr) return FALSE;
3539 spi_idx = SPI_SETWORKAREA_IDX;
3540 if (!spi_loaded[spi_idx])
3542 struct monitor *monitor;
3544 if (!lock_display_devices()) return FALSE;
3546 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
3548 if (!(monitor->flags & MONITORINFOF_PRIMARY)) continue;
3549 work_area = monitor->rc_work;
3550 break;
3553 unlock_display_devices();
3554 spi_loaded[spi_idx] = TRUE;
3556 *(RECT *)ptr = map_dpi_rect( work_area, system_dpi, get_thread_dpi() );
3557 ret = TRUE;
3558 TRACE("work area %s\n", wine_dbgstr_rect( &work_area ));
3559 break;
3562 WINE_SPI_FIXME(SPI_SETPENWINDOWS);
3564 case SPI_GETFILTERKEYS:
3566 LPFILTERKEYS filter_keys = ptr;
3567 WARN("SPI_GETFILTERKEYS not fully implemented\n");
3568 if (filter_keys && filter_keys->cbSize == sizeof(FILTERKEYS))
3570 /* Indicate that no FilterKeys feature available */
3571 filter_keys->dwFlags = 0;
3572 filter_keys->iWaitMSec = 0;
3573 filter_keys->iDelayMSec = 0;
3574 filter_keys->iRepeatMSec = 0;
3575 filter_keys->iBounceMSec = 0;
3576 ret = TRUE;
3578 break;
3580 WINE_SPI_FIXME(SPI_SETFILTERKEYS);
3582 case SPI_GETTOGGLEKEYS:
3584 LPTOGGLEKEYS toggle_keys = ptr;
3585 WARN("SPI_GETTOGGLEKEYS not fully implemented\n");
3586 if (toggle_keys && toggle_keys->cbSize == sizeof(TOGGLEKEYS))
3588 /* Indicate that no ToggleKeys feature available */
3589 toggle_keys->dwFlags = 0;
3590 ret = TRUE;
3592 break;
3595 WINE_SPI_FIXME(SPI_SETTOGGLEKEYS);
3597 case SPI_GETMOUSEKEYS:
3599 MOUSEKEYS *mouse_keys = ptr;
3600 WARN("SPI_GETMOUSEKEYS not fully implemented\n");
3601 if (mouse_keys && mouse_keys->cbSize == sizeof(MOUSEKEYS))
3603 /* Indicate that no MouseKeys feature available */
3604 mouse_keys->dwFlags = 0;
3605 mouse_keys->iMaxSpeed = 360;
3606 mouse_keys->iTimeToMaxSpeed = 1000;
3607 mouse_keys->iCtrlSpeed = 0;
3608 mouse_keys->dwReserved1 = 0;
3609 mouse_keys->dwReserved2 = 0;
3610 ret = TRUE;
3612 break;
3615 WINE_SPI_FIXME(SPI_SETMOUSEKEYS);
3617 case SPI_GETSHOWSOUNDS:
3618 ret = get_entry( &entry_SHOWSOUNDS, val, ptr );
3619 break;
3620 case SPI_SETSHOWSOUNDS:
3621 ret = set_entry( &entry_SHOWSOUNDS, val, ptr, winini );
3622 break;
3623 case SPI_GETSTICKYKEYS:
3625 STICKYKEYS *sticky_keys = ptr;
3626 WARN("SPI_GETSTICKYKEYS not fully implemented\n");
3627 if (sticky_keys && sticky_keys->cbSize == sizeof(STICKYKEYS))
3629 /* Indicate that no StickyKeys feature available */
3630 sticky_keys->dwFlags = 0;
3631 ret = TRUE;
3633 break;
3636 WINE_SPI_FIXME(SPI_SETSTICKYKEYS);
3638 case SPI_GETACCESSTIMEOUT:
3640 ACCESSTIMEOUT *access_timeout = ptr;
3641 WARN("SPI_GETACCESSTIMEOUT not fully implemented\n");
3642 if (access_timeout && access_timeout->cbSize == sizeof(ACCESSTIMEOUT))
3644 /* Indicate that no accessibility features timeout is available */
3645 access_timeout->dwFlags = 0;
3646 access_timeout->iTimeOutMSec = 0;
3647 ret = TRUE;
3649 break;
3652 WINE_SPI_FIXME(SPI_SETACCESSTIMEOUT);
3654 case SPI_GETSERIALKEYS:
3656 LPSERIALKEYSW serial_keys = ptr;
3657 WARN("SPI_GETSERIALKEYS not fully implemented\n");
3658 if (serial_keys && serial_keys->cbSize == sizeof(SERIALKEYSW))
3660 /* Indicate that no SerialKeys feature available */
3661 serial_keys->dwFlags = 0;
3662 serial_keys->lpszActivePort = NULL;
3663 serial_keys->lpszPort = NULL;
3664 serial_keys->iBaudRate = 0;
3665 serial_keys->iPortState = 0;
3666 ret = TRUE;
3668 break;
3671 WINE_SPI_FIXME(SPI_SETSERIALKEYS);
3673 case SPI_GETSOUNDSENTRY:
3675 SOUNDSENTRYW *sound_sentry = ptr;
3676 WARN("SPI_GETSOUNDSENTRY not fully implemented\n");
3677 if (sound_sentry && sound_sentry->cbSize == sizeof(SOUNDSENTRYW))
3679 /* Indicate that no SoundSentry feature available */
3680 sound_sentry->dwFlags = 0;
3681 sound_sentry->iFSTextEffect = 0;
3682 sound_sentry->iFSTextEffectMSec = 0;
3683 sound_sentry->iFSTextEffectColorBits = 0;
3684 sound_sentry->iFSGrafEffect = 0;
3685 sound_sentry->iFSGrafEffectMSec = 0;
3686 sound_sentry->iFSGrafEffectColor = 0;
3687 sound_sentry->iWindowsEffect = 0;
3688 sound_sentry->iWindowsEffectMSec = 0;
3689 sound_sentry->lpszWindowsEffectDLL = 0;
3690 sound_sentry->iWindowsEffectOrdinal = 0;
3691 ret = TRUE;
3693 break;
3696 WINE_SPI_FIXME(SPI_SETSOUNDSENTRY);
3698 case SPI_GETHIGHCONTRAST:
3700 HIGHCONTRASTW *high_contrast = ptr;
3701 WARN("SPI_GETHIGHCONTRAST not fully implemented\n");
3702 if (high_contrast && high_contrast->cbSize == sizeof(HIGHCONTRASTW))
3704 /* Indicate that no high contrast feature available */
3705 high_contrast->dwFlags = 0;
3706 high_contrast->lpszDefaultScheme = NULL;
3707 ret = TRUE;
3709 break;
3712 WINE_SPI_FIXME(SPI_SETHIGHCONTRAST);
3714 case SPI_GETKEYBOARDPREF:
3715 ret = get_entry( &entry_KEYBOARDPREF, val, ptr );
3716 break;
3717 case SPI_SETKEYBOARDPREF:
3718 ret = set_entry( &entry_KEYBOARDPREF, val, ptr, winini );
3719 break;
3720 case SPI_GETSCREENREADER:
3721 ret = get_entry( &entry_SCREENREADER, val, ptr );
3722 break;
3723 case SPI_SETSCREENREADER:
3724 ret = set_entry( &entry_SCREENREADER, val, ptr, winini );
3725 break;
3727 case SPI_GETANIMATION:
3729 ANIMATIONINFO *anim_info = ptr;
3731 /* Tell it "disabled" */
3732 if (anim_info && anim_info->cbSize == sizeof(ANIMATIONINFO))
3734 /* Minimize and restore animation is disabled (nonzero == enabled) */
3735 anim_info->iMinAnimate = 0;
3736 ret = TRUE;
3738 break;
3741 WINE_SPI_WARN(SPI_SETANIMATION);
3743 case SPI_GETFONTSMOOTHING:
3744 ret = get_entry( &entry_FONTSMOOTHING, val, ptr );
3745 if (ret) *(UINT *)ptr = (*(UINT *)ptr != 0);
3746 break;
3747 case SPI_SETFONTSMOOTHING:
3748 val = val ? 2 : 0; /* Win NT4/2k/XP behavior */
3749 ret = set_entry( &entry_FONTSMOOTHING, val, ptr, winini );
3750 break;
3751 case SPI_SETDRAGWIDTH:
3752 ret = set_entry( &entry_DRAGWIDTH, val, ptr, winini );
3753 break;
3754 case SPI_SETDRAGHEIGHT:
3755 ret = set_entry( &entry_DRAGHEIGHT, val, ptr, winini );
3756 break;
3758 WINE_SPI_FIXME(SPI_SETHANDHELD);
3759 WINE_SPI_FIXME(SPI_GETLOWPOWERTIMEOUT);
3760 WINE_SPI_FIXME(SPI_GETPOWEROFFTIMEOUT);
3761 WINE_SPI_FIXME(SPI_SETLOWPOWERTIMEOUT);
3762 WINE_SPI_FIXME(SPI_SETPOWEROFFTIMEOUT);
3764 case SPI_GETLOWPOWERACTIVE:
3765 ret = get_entry( &entry_LOWPOWERACTIVE, val, ptr );
3766 break;
3767 case SPI_SETLOWPOWERACTIVE:
3768 ret = set_entry( &entry_LOWPOWERACTIVE, val, ptr, winini );
3769 break;
3770 case SPI_GETPOWEROFFACTIVE:
3771 ret = get_entry( &entry_POWEROFFACTIVE, val, ptr );
3772 break;
3773 case SPI_SETPOWEROFFACTIVE:
3774 ret = set_entry( &entry_POWEROFFACTIVE, val, ptr, winini );
3775 break;
3777 WINE_SPI_FIXME(SPI_SETCURSORS);
3778 WINE_SPI_FIXME(SPI_SETICONS);
3780 case SPI_GETDEFAULTINPUTLANG:
3781 ret = NtUserGetKeyboardLayout(0) != 0;
3782 break;
3784 WINE_SPI_FIXME(SPI_SETDEFAULTINPUTLANG);
3785 WINE_SPI_FIXME(SPI_SETLANGTOGGLE);
3787 case SPI_GETWINDOWSEXTENSION:
3788 WARN( "pretend no support for Win9x Plus! for now.\n" );
3789 ret = FALSE; /* yes, this is the result value */
3790 break;
3791 case SPI_SETMOUSETRAILS:
3792 ret = set_entry( &entry_MOUSETRAILS, val, ptr, winini );
3793 break;
3794 case SPI_GETMOUSETRAILS:
3795 ret = get_entry( &entry_MOUSETRAILS, val, ptr );
3796 break;
3797 case SPI_GETSNAPTODEFBUTTON:
3798 ret = get_entry( &entry_SNAPTODEFBUTTON, val, ptr );
3799 break;
3800 case SPI_SETSNAPTODEFBUTTON:
3801 ret = set_entry( &entry_SNAPTODEFBUTTON, val, ptr, winini );
3802 break;
3803 case SPI_SETSCREENSAVERRUNNING:
3804 ret = set_entry( &entry_SCREENSAVERRUNNING, val, ptr, winini );
3805 break;
3806 case SPI_GETMOUSEHOVERWIDTH:
3807 ret = get_entry( &entry_MOUSEHOVERWIDTH, val, ptr );
3808 break;
3809 case SPI_SETMOUSEHOVERWIDTH:
3810 ret = set_entry( &entry_MOUSEHOVERWIDTH, val, ptr, winini );
3811 break;
3812 case SPI_GETMOUSEHOVERHEIGHT:
3813 ret = get_entry( &entry_MOUSEHOVERHEIGHT, val, ptr );
3814 break;
3815 case SPI_SETMOUSEHOVERHEIGHT:
3816 ret = set_entry( &entry_MOUSEHOVERHEIGHT, val, ptr, winini );
3817 break;
3818 case SPI_GETMOUSEHOVERTIME:
3819 ret = get_entry( &entry_MOUSEHOVERTIME, val, ptr );
3820 break;
3821 case SPI_SETMOUSEHOVERTIME:
3822 ret = set_entry( &entry_MOUSEHOVERTIME, val, ptr, winini );
3823 break;
3824 case SPI_GETWHEELSCROLLLINES:
3825 ret = get_entry( &entry_WHEELSCROLLLINES, val, ptr );
3826 break;
3827 case SPI_SETWHEELSCROLLLINES:
3828 ret = set_entry( &entry_WHEELSCROLLLINES, val, ptr, winini );
3829 break;
3830 case SPI_GETMENUSHOWDELAY:
3831 ret = get_entry( &entry_MENUSHOWDELAY, val, ptr );
3832 break;
3833 case SPI_SETMENUSHOWDELAY:
3834 ret = set_entry( &entry_MENUSHOWDELAY, val, ptr, winini );
3835 break;
3836 case SPI_GETWHEELSCROLLCHARS:
3837 ret = get_entry( &entry_WHEELSCROLLCHARS, val, ptr );
3838 break;
3839 case SPI_SETWHEELSCROLLCHARS:
3840 ret = set_entry( &entry_WHEELSCROLLCHARS, val, ptr, winini );
3841 break;
3843 WINE_SPI_FIXME(SPI_GETSHOWIMEUI);
3844 WINE_SPI_FIXME(SPI_SETSHOWIMEUI);
3846 case SPI_GETMOUSESPEED:
3847 ret = get_entry( &entry_MOUSESPEED, val, ptr );
3848 break;
3849 case SPI_SETMOUSESPEED:
3850 ret = set_entry( &entry_MOUSESPEED, val, ptr, winini );
3851 break;
3852 case SPI_GETSCREENSAVERRUNNING:
3853 ret = get_entry( &entry_SCREENSAVERRUNNING, val, ptr );
3854 break;
3855 case SPI_GETDESKWALLPAPER:
3856 ret = get_entry( &entry_DESKWALLPAPER, val, ptr );
3857 break;
3858 case SPI_GETACTIVEWINDOWTRACKING:
3859 ret = get_entry( &entry_ACTIVEWINDOWTRACKING, val, ptr );
3860 break;
3861 case SPI_SETACTIVEWINDOWTRACKING:
3862 ret = set_entry( &entry_ACTIVEWINDOWTRACKING, val, ptr, winini );
3863 break;
3864 case SPI_GETMENUANIMATION:
3865 ret = get_entry( &entry_MENUANIMATION, val, ptr );
3866 break;
3867 case SPI_SETMENUANIMATION:
3868 ret = set_entry( &entry_MENUANIMATION, val, ptr, winini );
3869 break;
3870 case SPI_GETCOMBOBOXANIMATION:
3871 ret = get_entry( &entry_COMBOBOXANIMATION, val, ptr );
3872 break;
3873 case SPI_SETCOMBOBOXANIMATION:
3874 ret = set_entry( &entry_COMBOBOXANIMATION, val, ptr, winini );
3875 break;
3876 case SPI_GETLISTBOXSMOOTHSCROLLING:
3877 ret = get_entry( &entry_LISTBOXSMOOTHSCROLLING, val, ptr );
3878 break;
3879 case SPI_SETLISTBOXSMOOTHSCROLLING:
3880 ret = set_entry( &entry_LISTBOXSMOOTHSCROLLING, val, ptr, winini );
3881 break;
3882 case SPI_GETGRADIENTCAPTIONS:
3883 ret = get_entry( &entry_GRADIENTCAPTIONS, val, ptr );
3884 break;
3885 case SPI_SETGRADIENTCAPTIONS:
3886 ret = set_entry( &entry_GRADIENTCAPTIONS, val, ptr, winini );
3887 break;
3888 case SPI_GETKEYBOARDCUES:
3889 ret = get_entry( &entry_KEYBOARDCUES, val, ptr );
3890 break;
3891 case SPI_SETKEYBOARDCUES:
3892 ret = set_entry( &entry_KEYBOARDCUES, val, ptr, winini );
3893 break;
3894 case SPI_GETACTIVEWNDTRKZORDER:
3895 ret = get_entry( &entry_ACTIVEWNDTRKZORDER, val, ptr );
3896 break;
3897 case SPI_SETACTIVEWNDTRKZORDER:
3898 ret = set_entry( &entry_ACTIVEWNDTRKZORDER, val, ptr, winini );
3899 break;
3900 case SPI_GETHOTTRACKING:
3901 ret = get_entry( &entry_HOTTRACKING, val, ptr );
3902 break;
3903 case SPI_SETHOTTRACKING:
3904 ret = set_entry( &entry_HOTTRACKING, val, ptr, winini );
3905 break;
3906 case SPI_GETMENUFADE:
3907 ret = get_entry( &entry_MENUFADE, val, ptr );
3908 break;
3909 case SPI_SETMENUFADE:
3910 ret = set_entry( &entry_MENUFADE, val, ptr, winini );
3911 break;
3912 case SPI_GETSELECTIONFADE:
3913 ret = get_entry( &entry_SELECTIONFADE, val, ptr );
3914 break;
3915 case SPI_SETSELECTIONFADE:
3916 ret = set_entry( &entry_SELECTIONFADE, val, ptr, winini );
3917 break;
3918 case SPI_GETTOOLTIPANIMATION:
3919 ret = get_entry( &entry_TOOLTIPANIMATION, val, ptr );
3920 break;
3921 case SPI_SETTOOLTIPANIMATION:
3922 ret = set_entry( &entry_TOOLTIPANIMATION, val, ptr, winini );
3923 break;
3924 case SPI_GETTOOLTIPFADE:
3925 ret = get_entry( &entry_TOOLTIPFADE, val, ptr );
3926 break;
3927 case SPI_SETTOOLTIPFADE:
3928 ret = set_entry( &entry_TOOLTIPFADE, val, ptr, winini );
3929 break;
3930 case SPI_GETCURSORSHADOW:
3931 ret = get_entry( &entry_CURSORSHADOW, val, ptr );
3932 break;
3933 case SPI_SETCURSORSHADOW:
3934 ret = set_entry( &entry_CURSORSHADOW, val, ptr, winini );
3935 break;
3936 case SPI_GETMOUSESONAR:
3937 ret = get_entry( &entry_MOUSESONAR, val, ptr );
3938 break;
3939 case SPI_SETMOUSESONAR:
3940 ret = set_entry( &entry_MOUSESONAR, val, ptr, winini );
3941 break;
3942 case SPI_GETMOUSECLICKLOCK:
3943 ret = get_entry( &entry_MOUSECLICKLOCK, val, ptr );
3944 break;
3945 case SPI_SETMOUSECLICKLOCK:
3946 ret = set_entry( &entry_MOUSECLICKLOCK, val, ptr, winini );
3947 break;
3948 case SPI_GETMOUSEVANISH:
3949 ret = get_entry( &entry_MOUSEVANISH, val, ptr );
3950 break;
3951 case SPI_SETMOUSEVANISH:
3952 ret = set_entry( &entry_MOUSEVANISH, val, ptr, winini );
3953 break;
3954 case SPI_GETFLATMENU:
3955 ret = get_entry( &entry_FLATMENU, val, ptr );
3956 break;
3957 case SPI_SETFLATMENU:
3958 ret = set_entry( &entry_FLATMENU, val, ptr, winini );
3959 break;
3960 case SPI_GETDROPSHADOW:
3961 ret = get_entry( &entry_DROPSHADOW, val, ptr );
3962 break;
3963 case SPI_SETDROPSHADOW:
3964 ret = set_entry( &entry_DROPSHADOW, val, ptr, winini );
3965 break;
3966 case SPI_GETBLOCKSENDINPUTRESETS:
3967 ret = get_entry( &entry_BLOCKSENDINPUTRESETS, val, ptr );
3968 break;
3969 case SPI_SETBLOCKSENDINPUTRESETS:
3970 ret = set_entry( &entry_BLOCKSENDINPUTRESETS, val, ptr, winini );
3971 break;
3972 case SPI_GETUIEFFECTS:
3973 ret = get_entry( &entry_UIEFFECTS, val, ptr );
3974 break;
3975 case SPI_SETUIEFFECTS:
3976 /* FIXME: this probably should mask other UI effect values when unset */
3977 ret = set_entry( &entry_UIEFFECTS, val, ptr, winini );
3978 break;
3979 case SPI_GETDISABLEOVERLAPPEDCONTENT:
3980 ret = get_entry( &entry_DISABLEOVERLAPPEDCONTENT, val, ptr );
3981 break;
3982 case SPI_SETDISABLEOVERLAPPEDCONTENT:
3983 ret = set_entry( &entry_DISABLEOVERLAPPEDCONTENT, val, ptr, winini );
3984 break;
3985 case SPI_GETCLIENTAREAANIMATION:
3986 ret = get_entry( &entry_CLIENTAREAANIMATION, val, ptr );
3987 break;
3988 case SPI_SETCLIENTAREAANIMATION:
3989 ret = set_entry( &entry_CLIENTAREAANIMATION, val, ptr, winini );
3990 break;
3991 case SPI_GETCLEARTYPE:
3992 ret = get_entry( &entry_CLEARTYPE, val, ptr );
3993 break;
3994 case SPI_SETCLEARTYPE:
3995 ret = set_entry( &entry_CLEARTYPE, val, ptr, winini );
3996 break;
3997 case SPI_GETSPEECHRECOGNITION:
3998 ret = get_entry( &entry_SPEECHRECOGNITION, val, ptr );
3999 break;
4000 case SPI_SETSPEECHRECOGNITION:
4001 ret = set_entry( &entry_SPEECHRECOGNITION, val, ptr, winini );
4002 break;
4003 case SPI_GETFOREGROUNDLOCKTIMEOUT:
4004 ret = get_entry( &entry_FOREGROUNDLOCKTIMEOUT, val, ptr );
4005 break;
4006 case SPI_SETFOREGROUNDLOCKTIMEOUT:
4007 /* FIXME: this should check that the calling thread
4008 * is able to change the foreground window */
4009 ret = set_entry( &entry_FOREGROUNDLOCKTIMEOUT, val, ptr, winini );
4010 break;
4011 case SPI_GETACTIVEWNDTRKTIMEOUT:
4012 ret = get_entry( &entry_ACTIVEWNDTRKTIMEOUT, val, ptr );
4013 break;
4014 case SPI_SETACTIVEWNDTRKTIMEOUT:
4015 ret = get_entry( &entry_ACTIVEWNDTRKTIMEOUT, val, ptr );
4016 break;
4017 case SPI_GETFOREGROUNDFLASHCOUNT:
4018 ret = get_entry( &entry_FOREGROUNDFLASHCOUNT, val, ptr );
4019 break;
4020 case SPI_SETFOREGROUNDFLASHCOUNT:
4021 ret = set_entry( &entry_FOREGROUNDFLASHCOUNT, val, ptr, winini );
4022 break;
4023 case SPI_GETCARETWIDTH:
4024 ret = get_entry( &entry_CARETWIDTH, val, ptr );
4025 break;
4026 case SPI_SETCARETWIDTH:
4027 ret = set_entry( &entry_CARETWIDTH, val, ptr, winini );
4028 break;
4029 case SPI_GETMOUSECLICKLOCKTIME:
4030 ret = get_entry( &entry_MOUSECLICKLOCKTIME, val, ptr );
4031 break;
4032 case SPI_SETMOUSECLICKLOCKTIME:
4033 ret = set_entry( &entry_MOUSECLICKLOCKTIME, val, ptr, winini );
4034 break;
4035 case SPI_GETFONTSMOOTHINGTYPE:
4036 ret = get_entry( &entry_FONTSMOOTHINGTYPE, val, ptr );
4037 break;
4038 case SPI_SETFONTSMOOTHINGTYPE:
4039 ret = set_entry( &entry_FONTSMOOTHINGTYPE, val, ptr, winini );
4040 break;
4041 case SPI_GETFONTSMOOTHINGCONTRAST:
4042 ret = get_entry( &entry_FONTSMOOTHINGCONTRAST, val, ptr );
4043 break;
4044 case SPI_SETFONTSMOOTHINGCONTRAST:
4045 ret = set_entry( &entry_FONTSMOOTHINGCONTRAST, val, ptr, winini );
4046 break;
4047 case SPI_GETFOCUSBORDERWIDTH:
4048 ret = get_entry( &entry_FOCUSBORDERWIDTH, val, ptr );
4049 break;
4050 case SPI_GETFOCUSBORDERHEIGHT:
4051 ret = get_entry( &entry_FOCUSBORDERHEIGHT, val, ptr );
4052 break;
4053 case SPI_SETFOCUSBORDERWIDTH:
4054 ret = set_entry( &entry_FOCUSBORDERWIDTH, val, ptr, winini );
4055 break;
4056 case SPI_SETFOCUSBORDERHEIGHT:
4057 ret = set_entry( &entry_FOCUSBORDERHEIGHT, val, ptr, winini );
4058 break;
4059 case SPI_GETFONTSMOOTHINGORIENTATION:
4060 ret = get_entry( &entry_FONTSMOOTHINGORIENTATION, val, ptr );
4061 break;
4062 case SPI_SETFONTSMOOTHINGORIENTATION:
4063 ret = set_entry( &entry_FONTSMOOTHINGORIENTATION, val, ptr, winini );
4064 break;
4065 case SPI_GETAUDIODESCRIPTION:
4067 AUDIODESCRIPTION *audio = ptr;
4068 if (audio && audio->cbSize == sizeof(AUDIODESCRIPTION) && val == sizeof(AUDIODESCRIPTION) )
4070 ret = get_entry( &entry_AUDIODESC_ON, 0, &audio->Enabled ) &&
4071 get_entry( &entry_AUDIODESC_LOCALE, 0, &audio->Locale );
4073 break;
4075 case SPI_SETAUDIODESCRIPTION:
4077 AUDIODESCRIPTION *audio = ptr;
4078 if (audio && audio->cbSize == sizeof(AUDIODESCRIPTION) && val == sizeof(AUDIODESCRIPTION) )
4080 ret = set_entry( &entry_AUDIODESC_ON, 0, &audio->Enabled, winini) &&
4081 set_entry( &entry_AUDIODESC_LOCALE, 0, &audio->Locale, winini );
4083 break;
4085 default:
4086 FIXME( "Unknown action: %u\n", action );
4087 SetLastError( ERROR_INVALID_SPI_VALUE );
4088 ret = FALSE;
4089 break;
4092 if (ret && (winini & SPIF_UPDATEINIFILE))
4094 static const WCHAR emptyW[1];
4095 if (winini & (SPIF_SENDWININICHANGE | SPIF_SENDCHANGE))
4096 user_callbacks->pSendMessageTimeoutW( HWND_BROADCAST, WM_SETTINGCHANGE,
4097 action, (LPARAM) emptyW,
4098 SMTO_ABORTIFHUNG, 2000, NULL );
4100 TRACE( "(%u, %u, %p, %u) ret %d\n", action, val, ptr, winini, ret );
4101 return ret;
4103 #undef WINE_SPI_FIXME
4104 #undef WINE_SPI_WARN
4107 int get_system_metrics( int index )
4109 NONCLIENTMETRICSW ncm;
4110 MINIMIZEDMETRICS mm;
4111 ICONMETRICSW im;
4112 RECT rect;
4113 UINT ret;
4114 HDC hdc;
4116 /* some metrics are dynamic */
4117 switch (index)
4119 case SM_CXVSCROLL:
4120 case SM_CYHSCROLL:
4121 get_entry( &entry_SCROLLWIDTH, 0, &ret );
4122 return max( ret, 8 );
4123 case SM_CYCAPTION:
4124 ncm.cbSize = sizeof(ncm);
4125 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4126 return ncm.iCaptionHeight + 1;
4127 case SM_CXBORDER:
4128 case SM_CYBORDER:
4129 /* SM_C{X,Y}BORDER always returns 1 regardless of 'BorderWidth' value in registry */
4130 return 1;
4131 case SM_CXDLGFRAME:
4132 case SM_CYDLGFRAME:
4133 return 3;
4134 case SM_CYVTHUMB:
4135 case SM_CXHTHUMB:
4136 case SM_CYVSCROLL:
4137 case SM_CXHSCROLL:
4138 get_entry( &entry_SCROLLHEIGHT, 0, &ret );
4139 return max( ret, 8 );
4140 case SM_CXICON:
4141 case SM_CYICON:
4142 return map_to_dpi( 32, get_system_dpi() );
4143 case SM_CXCURSOR:
4144 case SM_CYCURSOR:
4145 ret = map_to_dpi( 32, get_system_dpi() );
4146 if (ret >= 64) return 64;
4147 if (ret >= 48) return 48;
4148 return 32;
4149 case SM_CYMENU:
4150 ncm.cbSize = sizeof(ncm);
4151 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4152 return ncm.iMenuHeight + 1;
4153 case SM_CXFULLSCREEN:
4154 /* see the remark for SM_CXMAXIMIZED, at least this formulation is correct */
4155 return get_system_metrics( SM_CXMAXIMIZED ) - 2 * get_system_metrics( SM_CXFRAME );
4156 case SM_CYFULLSCREEN:
4157 /* see the remark for SM_CYMAXIMIZED, at least this formulation is
4158 * correct */
4159 return get_system_metrics( SM_CYMAXIMIZED ) - get_system_metrics( SM_CYMIN );
4160 case SM_CYKANJIWINDOW:
4161 return 0;
4162 case SM_MOUSEPRESENT:
4163 return 1;
4164 case SM_DEBUG:
4165 return 0;
4166 case SM_SWAPBUTTON:
4167 get_entry( &entry_MOUSEBUTTONSWAP, 0, &ret );
4168 return ret;
4169 case SM_RESERVED1:
4170 case SM_RESERVED2:
4171 case SM_RESERVED3:
4172 case SM_RESERVED4:
4173 return 0;
4174 case SM_CXMIN:
4175 ncm.cbSize = sizeof(ncm);
4176 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4177 hdc = get_display_dc();
4178 get_text_metr_size( hdc, &ncm.lfCaptionFont, NULL, &ret );
4179 release_display_dc( hdc );
4180 return 3 * ncm.iCaptionWidth + ncm.iCaptionHeight + 4 * ret +
4181 2 * get_system_metrics( SM_CXFRAME ) + 4;
4182 case SM_CYMIN:
4183 return get_system_metrics( SM_CYCAPTION ) + 2 * get_system_metrics( SM_CYFRAME );
4184 case SM_CXSIZE:
4185 get_entry( &entry_CAPTIONWIDTH, 0, &ret );
4186 return max( ret, 8 );
4187 case SM_CYSIZE:
4188 ncm.cbSize = sizeof(ncm);
4189 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4190 return ncm.iCaptionHeight;
4191 case SM_CXFRAME:
4192 get_entry( &entry_BORDER, 0, &ret );
4193 ret = max( ret, 1 );
4194 return get_system_metrics( SM_CXDLGFRAME ) + ret;
4195 case SM_CYFRAME:
4196 get_entry( &entry_BORDER, 0, &ret );
4197 ret = max( ret, 1 );
4198 return get_system_metrics( SM_CYDLGFRAME ) + ret;
4199 case SM_CXMINTRACK:
4200 return get_system_metrics( SM_CXMIN );
4201 case SM_CYMINTRACK:
4202 return get_system_metrics( SM_CYMIN );
4203 case SM_CXDOUBLECLK:
4204 get_entry( &entry_DOUBLECLKWIDTH, 0, &ret );
4205 return ret;
4206 case SM_CYDOUBLECLK:
4207 get_entry( &entry_DOUBLECLKHEIGHT, 0, &ret );
4208 return ret;
4209 case SM_CXICONSPACING:
4210 im.cbSize = sizeof(im);
4211 NtUserSystemParametersInfo( SPI_GETICONMETRICS, sizeof(im), &im, 0 );
4212 return im.iHorzSpacing;
4213 case SM_CYICONSPACING:
4214 im.cbSize = sizeof(im);
4215 NtUserSystemParametersInfo( SPI_GETICONMETRICS, sizeof(im), &im, 0 );
4216 return im.iVertSpacing;
4217 case SM_MENUDROPALIGNMENT:
4218 NtUserSystemParametersInfo( SPI_GETMENUDROPALIGNMENT, 0, &ret, 0 );
4219 return ret;
4220 case SM_PENWINDOWS:
4221 return 0;
4222 case SM_DBCSENABLED:
4223 return get_cptable(get_acp())->MaximumCharacterSize > 1;
4224 case SM_CMOUSEBUTTONS:
4225 return 3;
4226 case SM_SECURE:
4227 return 0;
4228 case SM_CXEDGE:
4229 return get_system_metrics( SM_CXBORDER ) + 1;
4230 case SM_CYEDGE:
4231 return get_system_metrics( SM_CYBORDER ) + 1;
4232 case SM_CXMINSPACING:
4233 mm.cbSize = sizeof(mm);
4234 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
4235 return get_system_metrics( SM_CXMINIMIZED ) + mm.iHorzGap;
4236 case SM_CYMINSPACING:
4237 mm.cbSize = sizeof(mm);
4238 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
4239 return get_system_metrics( SM_CYMINIMIZED ) + mm.iVertGap;
4240 case SM_CXSMICON:
4241 case SM_CYSMICON:
4242 return map_to_dpi( 16, get_system_dpi() ) & ~1;
4243 case SM_CYSMCAPTION:
4244 ncm.cbSize = sizeof(ncm);
4245 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4246 return ncm.iSmCaptionHeight + 1;
4247 case SM_CXSMSIZE:
4248 get_entry( &entry_SMCAPTIONWIDTH, 0, &ret );
4249 return ret;
4250 case SM_CYSMSIZE:
4251 ncm.cbSize = sizeof(ncm);
4252 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4253 return ncm.iSmCaptionHeight;
4254 case SM_CXMENUSIZE:
4255 get_entry( &entry_MENUWIDTH, 0, &ret );
4256 return ret;
4257 case SM_CYMENUSIZE:
4258 ncm.cbSize = sizeof(ncm);
4259 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4260 return ncm.iMenuHeight;
4261 case SM_ARRANGE:
4262 mm.cbSize = sizeof(mm);
4263 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
4264 return mm.iArrange;
4265 case SM_CXMINIMIZED:
4266 mm.cbSize = sizeof(mm);
4267 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
4268 return mm.iWidth + 6;
4269 case SM_CYMINIMIZED:
4270 ncm.cbSize = sizeof(ncm);
4271 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4272 return ncm.iCaptionHeight + 6;
4273 case SM_CXMAXTRACK:
4274 return get_system_metrics( SM_CXVIRTUALSCREEN ) + 4 + 2 * get_system_metrics( SM_CXFRAME );
4275 case SM_CYMAXTRACK:
4276 return get_system_metrics( SM_CYVIRTUALSCREEN ) + 4 + 2 * get_system_metrics( SM_CYFRAME );
4277 case SM_CXMAXIMIZED:
4278 /* FIXME: subtract the width of any vertical application toolbars*/
4279 return get_system_metrics( SM_CXSCREEN ) + 2 * get_system_metrics( SM_CXFRAME );
4280 case SM_CYMAXIMIZED:
4281 /* FIXME: subtract the width of any horizontal application toolbars*/
4282 return get_system_metrics( SM_CYSCREEN ) + 2 * get_system_metrics( SM_CYCAPTION );
4283 case SM_NETWORK:
4284 return 3; /* FIXME */
4285 case SM_CLEANBOOT:
4286 return 0; /* 0 = ok, 1 = failsafe, 2 = failsafe + network */
4287 case SM_CXDRAG:
4288 get_entry( &entry_DRAGWIDTH, 0, &ret );
4289 return ret;
4290 case SM_CYDRAG:
4291 get_entry( &entry_DRAGHEIGHT, 0, &ret );
4292 return ret;
4293 case SM_SHOWSOUNDS:
4294 get_entry( &entry_SHOWSOUNDS, 0, &ret );
4295 return ret;
4296 case SM_CXMENUCHECK:
4297 case SM_CYMENUCHECK:
4299 TEXTMETRICW tm;
4300 ncm.cbSize = sizeof(ncm);
4301 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4302 hdc = get_display_dc();
4303 get_text_metr_size( hdc, &ncm.lfMenuFont, &tm, NULL );
4304 release_display_dc( hdc );
4305 return tm.tmHeight <= 0 ? 13 : ((tm.tmHeight + tm.tmExternalLeading + 1) / 2) * 2 - 1;
4307 case SM_SLOWMACHINE:
4308 return 0; /* Never true */
4309 case SM_MIDEASTENABLED:
4310 return 0; /* FIXME */
4311 case SM_MOUSEWHEELPRESENT:
4312 return 1;
4313 case SM_CXSCREEN:
4314 rect = get_primary_monitor_rect( get_thread_dpi() );
4315 return rect.right - rect.left;
4316 case SM_CYSCREEN:
4317 rect = get_primary_monitor_rect( get_thread_dpi() );
4318 return rect.bottom - rect.top;
4319 case SM_XVIRTUALSCREEN:
4320 rect = get_virtual_screen_rect( get_thread_dpi() );
4321 return rect.left;
4322 case SM_YVIRTUALSCREEN:
4323 rect = get_virtual_screen_rect( get_thread_dpi() );
4324 return rect.top;
4325 case SM_CXVIRTUALSCREEN:
4326 rect = get_virtual_screen_rect( get_thread_dpi() );
4327 return rect.right - rect.left;
4328 case SM_CYVIRTUALSCREEN:
4329 rect = get_virtual_screen_rect( get_thread_dpi() );
4330 return rect.bottom - rect.top;
4331 case SM_CMONITORS:
4332 if (!lock_display_devices()) return FALSE;
4333 ret = active_monitor_count();
4334 unlock_display_devices();
4335 return ret;
4336 case SM_SAMEDISPLAYFORMAT:
4337 return 1;
4338 case SM_IMMENABLED:
4339 return 0; /* FIXME */
4340 case SM_CXFOCUSBORDER:
4341 case SM_CYFOCUSBORDER:
4342 return 1;
4343 case SM_TABLETPC:
4344 case SM_MEDIACENTER:
4345 return 0;
4346 case SM_CMETRICS:
4347 return SM_CMETRICS;
4348 default:
4349 return 0;
4353 static int get_system_metrics_for_dpi( int index, unsigned int dpi )
4355 NONCLIENTMETRICSW ncm;
4356 ICONMETRICSW im;
4357 UINT ret;
4358 HDC hdc;
4360 /* some metrics are dynamic */
4361 switch (index)
4363 case SM_CXVSCROLL:
4364 case SM_CYHSCROLL:
4365 get_entry_dpi( &entry_SCROLLWIDTH, 0, &ret, dpi );
4366 return max( ret, 8 );
4367 case SM_CYCAPTION:
4368 ncm.cbSize = sizeof(ncm);
4369 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4370 return ncm.iCaptionHeight + 1;
4371 case SM_CYVTHUMB:
4372 case SM_CXHTHUMB:
4373 case SM_CYVSCROLL:
4374 case SM_CXHSCROLL:
4375 get_entry_dpi( &entry_SCROLLHEIGHT, 0, &ret, dpi );
4376 return max( ret, 8 );
4377 case SM_CXICON:
4378 case SM_CYICON:
4379 return map_to_dpi( 32, dpi );
4380 case SM_CXCURSOR:
4381 case SM_CYCURSOR:
4382 ret = map_to_dpi( 32, dpi );
4383 if (ret >= 64) return 64;
4384 if (ret >= 48) return 48;
4385 return 32;
4386 case SM_CYMENU:
4387 ncm.cbSize = sizeof(ncm);
4388 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4389 return ncm.iMenuHeight + 1;
4390 case SM_CXSIZE:
4391 get_entry_dpi( &entry_CAPTIONWIDTH, 0, &ret, dpi );
4392 return max( ret, 8 );
4393 case SM_CYSIZE:
4394 ncm.cbSize = sizeof(ncm);
4395 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4396 return ncm.iCaptionHeight;
4397 case SM_CXFRAME:
4398 get_entry_dpi( &entry_BORDER, 0, &ret, dpi );
4399 ret = max( ret, 1 );
4400 return get_system_metrics_for_dpi( SM_CXDLGFRAME, dpi ) + ret;
4401 case SM_CYFRAME:
4402 get_entry_dpi( &entry_BORDER, 0, &ret, dpi );
4403 ret = max( ret, 1 );
4404 return get_system_metrics_for_dpi( SM_CYDLGFRAME, dpi ) + ret;
4405 case SM_CXICONSPACING:
4406 im.cbSize = sizeof(im);
4407 NtUserSystemParametersInfoForDpi( SPI_GETICONMETRICS, sizeof(im), &im, 0, dpi );
4408 return im.iHorzSpacing;
4409 case SM_CYICONSPACING:
4410 im.cbSize = sizeof(im);
4411 NtUserSystemParametersInfoForDpi( SPI_GETICONMETRICS, sizeof(im), &im, 0, dpi );
4412 return im.iVertSpacing;
4413 case SM_CXSMICON:
4414 case SM_CYSMICON:
4415 return map_to_dpi( 16, dpi ) & ~1;
4416 case SM_CYSMCAPTION:
4417 ncm.cbSize = sizeof(ncm);
4418 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4419 return ncm.iSmCaptionHeight + 1;
4420 case SM_CXSMSIZE:
4421 get_entry_dpi( &entry_SMCAPTIONWIDTH, 0, &ret, dpi );
4422 return ret;
4423 case SM_CYSMSIZE:
4424 ncm.cbSize = sizeof(ncm);
4425 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4426 return ncm.iSmCaptionHeight;
4427 case SM_CXMENUSIZE:
4428 get_entry_dpi( &entry_MENUWIDTH, 0, &ret, dpi );
4429 return ret;
4430 case SM_CYMENUSIZE:
4431 ncm.cbSize = sizeof(ncm);
4432 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4433 return ncm.iMenuHeight;
4434 case SM_CXMENUCHECK:
4435 case SM_CYMENUCHECK:
4437 TEXTMETRICW tm;
4438 ncm.cbSize = sizeof(ncm);
4439 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4440 hdc = get_display_dc();
4441 get_text_metr_size( hdc, &ncm.lfMenuFont, &tm, NULL);
4442 release_display_dc( hdc );
4443 return tm.tmHeight <= 0 ? 13 : ((tm.tmHeight + tm.tmExternalLeading - 1) | 1);
4445 default:
4446 return get_system_metrics( index );
4450 static COLORREF get_sys_color( int index )
4452 COLORREF ret = 0;
4454 if (index >= 0 && index < ARRAY_SIZE( system_colors ))
4455 get_entry( &system_colors[index], 0, &ret );
4456 return ret;
4459 static HBRUSH get_55aa_brush(void)
4461 static const WORD pattern[] = { 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa };
4462 static HBRUSH brush_55aa;
4464 if (!brush_55aa)
4466 HBITMAP bitmap = NtGdiCreateBitmap( 8, 8, 1, 1, pattern );
4467 HBRUSH brush = NtGdiCreatePatternBrushInternal( bitmap, FALSE, FALSE );
4468 NtGdiDeleteObjectApp( bitmap );
4469 make_gdi_object_system( brush, TRUE );
4470 if (InterlockedCompareExchangePointer( (void **)&brush_55aa, brush, 0 ))
4472 make_gdi_object_system( brush, FALSE );
4473 NtGdiDeleteObjectApp( brush );
4476 return brush_55aa;
4479 static HBRUSH get_sys_color_brush( unsigned int index )
4481 if (index == COLOR_55AA_BRUSH) return get_55aa_brush();
4482 if (index >= ARRAY_SIZE( system_colors )) return 0;
4484 if (!system_colors[index].brush)
4486 HBRUSH brush = NtGdiCreateSolidBrush( get_sys_color( index ), NULL );
4487 make_gdi_object_system( brush, TRUE );
4488 if (InterlockedCompareExchangePointer( (void **)&system_colors[index].brush, brush, 0 ))
4490 make_gdi_object_system( brush, FALSE );
4491 NtGdiDeleteObjectApp( brush );
4494 return system_colors[index].brush;
4497 static HPEN get_sys_color_pen( unsigned int index )
4499 if (index >= ARRAY_SIZE( system_colors )) return 0;
4501 if (!system_colors[index].pen)
4503 HPEN pen = NtGdiCreatePen( PS_SOLID, 1, get_sys_color( index ), NULL );
4504 make_gdi_object_system( pen, TRUE );
4505 if (InterlockedCompareExchangePointer( (void **)&system_colors[index].pen, pen, 0 ))
4507 make_gdi_object_system( pen, FALSE );
4508 NtGdiDeleteObjectApp( pen );
4511 return system_colors[index].pen;
4514 /**********************************************************************
4515 * NtUserGetDoubleClickTime (win32u.@)
4517 UINT WINAPI NtUserGetDoubleClickTime(void)
4519 UINT time = 0;
4521 get_entry( &entry_DOUBLECLICKTIME, 0, &time );
4522 if (!time) time = 500;
4523 return time;
4526 /*************************************************************************
4527 * NtUserSetSysColors (win32u.@)
4529 BOOL WINAPI NtUserSetSysColors( INT count, const INT *colors, const COLORREF *values )
4531 int i;
4533 if (IS_INTRESOURCE(colors)) return FALSE; /* stupid app passes a color instead of an array */
4535 for (i = 0; i < count; i++)
4536 if (colors[i] >= 0 && colors[i] <= ARRAY_SIZE( system_colors ))
4537 set_entry( &system_colors[colors[i]], values[i], 0, 0 );
4539 /* Send WM_SYSCOLORCHANGE message to all windows */
4540 user_callbacks->pSendMessageTimeoutW( HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0,
4541 SMTO_ABORTIFHUNG, 2000, NULL );
4542 /* Repaint affected portions of all visible windows */
4543 NtUserRedrawWindow( 0, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN );
4544 return TRUE;
4548 static DPI_AWARENESS dpi_awareness;
4550 /***********************************************************************
4551 * NtUserSetProcessDpiAwarenessContext (win32u.@)
4553 BOOL WINAPI NtUserSetProcessDpiAwarenessContext( ULONG awareness, ULONG unknown )
4555 switch (awareness)
4557 case NTUSER_DPI_UNAWARE:
4558 case NTUSER_DPI_SYSTEM_AWARE:
4559 case NTUSER_DPI_PER_MONITOR_AWARE:
4560 case NTUSER_DPI_PER_MONITOR_AWARE_V2:
4561 case NTUSER_DPI_PER_UNAWARE_GDISCALED:
4562 break;
4563 default:
4564 SetLastError( ERROR_INVALID_PARAMETER );
4565 return FALSE;
4568 return !InterlockedCompareExchange( &dpi_awareness, awareness, 0 );
4571 /***********************************************************************
4572 * NtUserGetProcessDpiAwarenessContext (win32u.@)
4574 ULONG WINAPI NtUserGetProcessDpiAwarenessContext( HANDLE process )
4576 if (process && process != GetCurrentProcess())
4578 WARN( "not supported on other process %p\n", process );
4579 return NTUSER_DPI_UNAWARE;
4582 if (!dpi_awareness) return NTUSER_DPI_UNAWARE;
4583 return dpi_awareness;
4586 static BOOL message_beep( UINT i )
4588 BOOL active = TRUE;
4589 NtUserSystemParametersInfo( SPI_GETBEEP, 0, &active, FALSE );
4590 if (active) user_driver->pBeep();
4591 return TRUE;
4594 static DWORD exiting_thread_id;
4596 /**********************************************************************
4597 * is_exiting_thread
4599 BOOL is_exiting_thread( DWORD tid )
4601 return tid == exiting_thread_id;
4604 static void thread_detach(void)
4606 struct user_thread_info *thread_info = get_user_thread_info();
4608 user_driver->pThreadDetach();
4610 free( thread_info->key_state );
4611 thread_info->key_state = 0;
4613 destroy_thread_windows();
4614 NtClose( thread_info->server_queue );
4616 exiting_thread_id = 0;
4619 /***********************************************************************
4620 * NtUserCallNoParam (win32u.@)
4622 ULONG_PTR WINAPI NtUserCallNoParam( ULONG code )
4624 switch(code)
4626 case NtUserCreateMenu:
4627 return HandleToUlong( create_menu() );
4628 case NtUserGetDesktopWindow:
4629 return HandleToUlong( get_desktop_window() );
4630 case NtUserGetInputState:
4631 return get_input_state();
4632 case NtUserReleaseCapture:
4633 return release_capture();
4634 /* temporary exports */
4635 case NtUserExitingThread:
4636 exiting_thread_id = GetCurrentThreadId();
4637 return 0;
4638 case NtUserThreadDetach:
4639 thread_detach();
4640 return 0;
4641 default:
4642 FIXME( "invalid code %u\n", code );
4643 return 0;
4647 /***********************************************************************
4648 * NtUserCallOneParam (win32u.@)
4650 ULONG_PTR WINAPI NtUserCallOneParam( ULONG_PTR arg, ULONG code )
4652 switch(code)
4654 case NtUserBeginDeferWindowPos:
4655 return HandleToUlong( begin_defer_window_pos( arg ));
4656 case NtUserCreateCursorIcon:
4657 return HandleToUlong( alloc_cursoricon_handle( arg ));
4658 case NtUserDispatchMessageA:
4659 return dispatch_message( (const MSG *)arg, TRUE );
4660 case NtUserEnableDC:
4661 return set_dce_flags( UlongToHandle(arg), DCHF_ENABLEDC );
4662 case NtUserGetClipCursor:
4663 return get_clip_cursor( (RECT *)arg );
4664 case NtUserGetCursorPos:
4665 return get_cursor_pos( (POINT *)arg );
4666 case NtUserGetIconParam:
4667 return get_icon_param( UlongToHandle(arg) );
4668 case NtUserGetSysColor:
4669 return get_sys_color( arg );
4670 case NtUserRealizePalette:
4671 return realize_palette( UlongToHandle(arg) );
4672 case NtUserGetPrimaryMonitorRect:
4673 *(RECT *)arg = get_primary_monitor_rect( 0 );
4674 return 1;
4675 case NtUserGetSysColorBrush:
4676 return HandleToUlong( get_sys_color_brush(arg) );
4677 case NtUserGetSysColorPen:
4678 return HandleToUlong( get_sys_color_pen(arg) );
4679 case NtUserGetSystemMetrics:
4680 return get_system_metrics( arg );
4681 case NtUserGetVirtualScreenRect:
4682 *(RECT *)arg = get_virtual_screen_rect( 0 );
4683 return 1;
4684 case NtUserMessageBeep:
4685 return message_beep( arg );
4686 /* temporary exports */
4687 case NtUserCallHooks:
4689 const struct win_hook_params *params = (struct win_hook_params *)arg;
4690 return call_hooks( params->id, params->code, params->wparam, params->lparam,
4691 params->next_unicode );
4693 case NtUserFlushWindowSurfaces:
4694 flush_window_surfaces( arg );
4695 return 0;
4696 case NtUserGetDeskPattern:
4697 return get_entry( &entry_DESKPATTERN, 256, (WCHAR *)arg );
4698 case NtUserGetWinProcPtr:
4699 return (UINT_PTR)get_winproc_ptr( UlongToHandle(arg) );
4700 case NtUserHandleInternalMessage:
4702 MSG *msg = (MSG *)arg;
4703 return handle_internal_message( msg->hwnd, msg->message, msg->wParam, msg->lParam );
4705 case NtUserIncrementKeyStateCounter:
4706 return InterlockedAdd( &global_key_state_counter, arg );
4707 case NtUserLock:
4708 switch( arg )
4710 case 0: user_lock(); return 0;
4711 case 1: user_unlock(); return 0;
4712 default: user_check_not_lock(); return 0;
4714 case NtUserSetCallbacks:
4715 return (UINT_PTR)InterlockedExchangePointer( (void **)&user_callbacks, (void *)arg );
4716 case NtUserSpyGetVKeyName:
4717 return (UINT_PTR)debugstr_vkey_name( arg );
4718 default:
4719 FIXME( "invalid code %u\n", code );
4720 return 0;
4724 /***********************************************************************
4725 * NtUserCallTwoParam (win32u.@)
4727 ULONG_PTR WINAPI NtUserCallTwoParam( ULONG_PTR arg1, ULONG_PTR arg2, ULONG code )
4729 switch(code)
4731 case NtUserGetMonitorInfo:
4732 return get_monitor_info( UlongToHandle(arg1), (MONITORINFO *)arg2 );
4733 case NtUserGetSystemMetricsForDpi:
4734 return get_system_metrics_for_dpi( arg1, arg2 );
4735 case NtUserMirrorRgn:
4736 return mirror_window_region( UlongToHandle(arg1), UlongToHandle(arg2) );
4737 case NtUserMonitorFromRect:
4738 return HandleToUlong( monitor_from_rect( (const RECT *)arg1, arg2, get_thread_dpi() ));
4739 case NtUserReplyMessage:
4740 return reply_message_result( arg1, (MSG *)arg2 );
4741 case NtUserSetIconParam:
4742 return set_icon_param( UlongToHandle(arg1), arg2 );
4743 case NtUserUnhookWindowsHook:
4744 return unhook_windows_hook( arg1, (HOOKPROC)arg2 );
4745 /* temporary exports */
4746 case NtUserAllocWinProc:
4747 return (UINT_PTR)alloc_winproc( (WNDPROC)arg1, arg2 );
4748 case NtUserGetHandlePtr:
4749 return (UINT_PTR)get_user_handle_ptr( UlongToHandle(arg1), arg2 );
4750 default:
4751 FIXME( "invalid code %u\n", code );
4752 return 0;