userenv/tests: Enable compilation with long types.
[wine.git] / dlls / win32u / sysparams.c
blob124e6781ad10e0dfb65634e7cf77ce067fbe08c3
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 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 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_thread_dpi_awareness
1385 static DPI_AWARENESS get_thread_dpi_awareness(void)
1387 struct user_thread_info *info = get_user_thread_info();
1388 ULONG_PTR context = info->dpi_awareness;
1390 if (!context) context = NtUserGetProcessDpiAwarenessContext( NULL );
1392 switch (context)
1394 case 0x10:
1395 case 0x11:
1396 case 0x12:
1397 case 0x80000010:
1398 case 0x80000011:
1399 case 0x80000012:
1400 return context & 3;
1401 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE:
1402 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE:
1403 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE:
1404 return ~context;
1405 default:
1406 return DPI_AWARENESS_INVALID;
1410 /**********************************************************************
1411 * get_thread_dpi
1413 UINT get_thread_dpi(void)
1415 switch (get_thread_dpi_awareness())
1417 case DPI_AWARENESS_UNAWARE: return USER_DEFAULT_SCREEN_DPI;
1418 case DPI_AWARENESS_SYSTEM_AWARE: return system_dpi;
1419 default: return 0; /* no scaling */
1423 /* see GetDpiForSystem */
1424 UINT get_system_dpi(void)
1426 if (get_thread_dpi_awareness() == DPI_AWARENESS_UNAWARE) return USER_DEFAULT_SCREEN_DPI;
1427 return system_dpi;
1430 /**********************************************************************
1431 * map_dpi_rect
1433 RECT map_dpi_rect( RECT rect, UINT dpi_from, UINT dpi_to )
1435 if (dpi_from && dpi_to && dpi_from != dpi_to)
1437 rect.left = muldiv( rect.left, dpi_to, dpi_from );
1438 rect.top = muldiv( rect.top, dpi_to, dpi_from );
1439 rect.right = muldiv( rect.right, dpi_to, dpi_from );
1440 rect.bottom = muldiv( rect.bottom, dpi_to, dpi_from );
1442 return rect;
1445 /**********************************************************************
1446 * map_dpi_point
1448 POINT map_dpi_point( POINT pt, UINT dpi_from, UINT dpi_to )
1450 if (dpi_from && dpi_to && dpi_from != dpi_to)
1452 pt.x = muldiv( pt.x, dpi_to, dpi_from );
1453 pt.y = muldiv( pt.y, dpi_to, dpi_from );
1455 return pt;
1458 /* map value from system dpi to standard 96 dpi for storing in the registry */
1459 static int map_from_system_dpi( int val )
1461 return muldiv( val, USER_DEFAULT_SCREEN_DPI, get_system_dpi() );
1464 /* map value from 96 dpi to system or custom dpi */
1465 static int map_to_dpi( int val, UINT dpi )
1467 if (!dpi) dpi = get_system_dpi();
1468 return muldiv( val, dpi, USER_DEFAULT_SCREEN_DPI );
1471 RECT get_virtual_screen_rect( UINT dpi )
1473 struct monitor *monitor;
1474 RECT rect = {0};
1476 if (!lock_display_devices()) return rect;
1478 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
1480 union_rect( &rect, &rect, &monitor->rc_monitor );
1483 unlock_display_devices();
1485 if (dpi) rect = map_dpi_rect( rect, system_dpi, dpi );
1486 return rect;
1489 RECT get_display_rect( const WCHAR *display )
1491 struct monitor *monitor;
1492 RECT rect = {0};
1494 if (!lock_display_devices()) return rect;
1496 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
1498 if (!monitor->adapter || wcsicmp( monitor->adapter->dev.device_name, display )) continue;
1499 rect = monitor->rc_monitor;
1500 break;
1503 unlock_display_devices();
1504 return map_dpi_rect( rect, system_dpi, get_thread_dpi() );
1507 static RECT get_primary_monitor_rect( UINT dpi )
1509 struct monitor *monitor;
1510 RECT rect = {0};
1512 if (!lock_display_devices()) return rect;
1514 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
1516 if (!(monitor->flags & MONITORINFOF_PRIMARY)) continue;
1517 rect = monitor->rc_monitor;
1518 break;
1521 unlock_display_devices();
1522 return map_dpi_rect( rect, system_dpi, dpi );
1525 /**********************************************************************
1526 * NtUserGetDisplayConfigBufferSizes (win32u.@)
1528 LONG WINAPI NtUserGetDisplayConfigBufferSizes( UINT32 flags, UINT32 *num_path_info,
1529 UINT32 *num_mode_info )
1531 struct monitor *monitor;
1532 UINT32 count = 0;
1534 TRACE( "(0x%x %p %p)\n", flags, num_path_info, num_mode_info );
1536 if (!num_path_info || !num_mode_info)
1537 return ERROR_INVALID_PARAMETER;
1539 *num_path_info = 0;
1541 switch (flags)
1543 case QDC_ALL_PATHS:
1544 case QDC_ONLY_ACTIVE_PATHS:
1545 case QDC_DATABASE_CURRENT:
1546 break;
1547 default:
1548 return ERROR_INVALID_PARAMETER;
1551 /* FIXME: semi-stub */
1552 if (flags != QDC_ONLY_ACTIVE_PATHS)
1553 FIXME( "only returning active paths\n" );
1555 if (lock_display_devices())
1557 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
1559 if (!(monitor->dev.state_flags & DISPLAY_DEVICE_ACTIVE))
1560 continue;
1561 count++;
1563 unlock_display_devices();
1566 *num_path_info = count;
1567 *num_mode_info = count * 2;
1568 TRACE( "returning %u paths %u modes\n", *num_path_info, *num_mode_info );
1569 return ERROR_SUCCESS;
1572 static struct adapter *find_adapter( UNICODE_STRING *name )
1574 struct adapter *adapter;
1576 LIST_FOR_EACH_ENTRY(adapter, &adapters, struct adapter, entry)
1578 if (!name || !name->Length) return adapter; /* use primary adapter */
1579 if (!wcsnicmp( name->Buffer, adapter->dev.device_name, name->Length / sizeof(WCHAR) ) &&
1580 !adapter->dev.device_name[name->Length / sizeof(WCHAR)])
1581 return adapter;
1583 return NULL;
1586 /***********************************************************************
1587 * NtUserEnumDisplayDevices (win32u.@)
1589 NTSTATUS WINAPI NtUserEnumDisplayDevices( UNICODE_STRING *device, DWORD index,
1590 DISPLAY_DEVICEW *info, DWORD flags )
1592 struct display_device *found = NULL;
1593 struct adapter *adapter;
1594 struct monitor *monitor;
1596 TRACE( "%s %u %p %#x\n", debugstr_us( device ), index, info, flags );
1598 if (!info || !info->cb) return STATUS_UNSUCCESSFUL;
1600 if (!lock_display_devices()) return STATUS_UNSUCCESSFUL;
1602 if (!device || !device->Length)
1604 /* Enumerate adapters */
1605 LIST_FOR_EACH_ENTRY(adapter, &adapters, struct adapter, entry)
1607 if (index == adapter->id)
1609 found = &adapter->dev;
1610 break;
1614 else if ((adapter = find_adapter( device )))
1616 /* Enumerate monitors */
1617 LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry)
1619 if (monitor->adapter == adapter && index == monitor->id)
1621 found = &monitor->dev;
1622 break;
1627 if (found)
1629 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceName) + sizeof(info->DeviceName))
1630 lstrcpyW( info->DeviceName, found->device_name );
1631 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceString) + sizeof(info->DeviceString))
1632 lstrcpyW( info->DeviceString, found->device_string );
1633 if (info->cb >= offsetof(DISPLAY_DEVICEW, StateFlags) + sizeof(info->StateFlags))
1634 info->StateFlags = found->state_flags;
1635 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->DeviceID))
1636 lstrcpyW( info->DeviceID, (flags & EDD_GET_DEVICE_INTERFACE_NAME)
1637 ? found->interface_name : found->device_id );
1638 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(info->DeviceKey))
1639 lstrcpyW( info->DeviceKey, found->device_key );
1641 unlock_display_devices();
1642 return found ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
1645 #define _X_FIELD(prefix, bits) \
1646 if ((fields) & prefix##_##bits) \
1648 p += sprintf( p, "%s%s", first ? "" : ",", #bits ); \
1649 first = FALSE; \
1652 static const char *_CDS_flags( DWORD fields )
1654 BOOL first = TRUE;
1655 CHAR buf[128];
1656 CHAR *p = buf;
1658 _X_FIELD(CDS, UPDATEREGISTRY)
1659 _X_FIELD(CDS, TEST)
1660 _X_FIELD(CDS, FULLSCREEN)
1661 _X_FIELD(CDS, GLOBAL)
1662 _X_FIELD(CDS, SET_PRIMARY)
1663 _X_FIELD(CDS, VIDEOPARAMETERS)
1664 _X_FIELD(CDS, ENABLE_UNSAFE_MODES)
1665 _X_FIELD(CDS, DISABLE_UNSAFE_MODES)
1666 _X_FIELD(CDS, RESET)
1667 _X_FIELD(CDS, RESET_EX)
1668 _X_FIELD(CDS, NORESET)
1670 *p = 0;
1671 return wine_dbg_sprintf( "%s", buf );
1674 static const char *_DM_fields( DWORD fields )
1676 BOOL first = TRUE;
1677 CHAR buf[128];
1678 CHAR *p = buf;
1680 _X_FIELD(DM, BITSPERPEL)
1681 _X_FIELD(DM, PELSWIDTH)
1682 _X_FIELD(DM, PELSHEIGHT)
1683 _X_FIELD(DM, DISPLAYFLAGS)
1684 _X_FIELD(DM, DISPLAYFREQUENCY)
1685 _X_FIELD(DM, POSITION)
1686 _X_FIELD(DM, DISPLAYORIENTATION)
1688 *p = 0;
1689 return wine_dbg_sprintf( "%s", buf );
1692 #undef _X_FIELD
1694 static void trace_devmode( const DEVMODEW *devmode )
1696 TRACE( "dmFields=%s ", _DM_fields(devmode->dmFields) );
1697 if (devmode->dmFields & DM_BITSPERPEL)
1698 TRACE( "dmBitsPerPel=%u ", devmode->dmBitsPerPel );
1699 if (devmode->dmFields & DM_PELSWIDTH)
1700 TRACE( "dmPelsWidth=%u ", devmode->dmPelsWidth );
1701 if (devmode->dmFields & DM_PELSHEIGHT)
1702 TRACE( "dmPelsHeight=%u ", devmode->dmPelsHeight );
1703 if (devmode->dmFields & DM_DISPLAYFREQUENCY)
1704 TRACE( "dmDisplayFrequency=%u ", devmode->dmDisplayFrequency );
1705 if (devmode->dmFields & DM_POSITION)
1706 TRACE( "dmPosition=(%d,%d) ", devmode->dmPosition.x, devmode->dmPosition.y );
1707 if (devmode->dmFields & DM_DISPLAYFLAGS)
1708 TRACE( "dmDisplayFlags=%#x ", devmode->dmDisplayFlags );
1709 if (devmode->dmFields & DM_DISPLAYORIENTATION)
1710 TRACE( "dmDisplayOrientation=%u ", devmode->dmDisplayOrientation );
1711 TRACE("\n");
1714 static BOOL is_detached_mode( const DEVMODEW *mode )
1716 return mode->dmFields & DM_POSITION &&
1717 mode->dmFields & DM_PELSWIDTH &&
1718 mode->dmFields & DM_PELSHEIGHT &&
1719 mode->dmPelsWidth == 0 &&
1720 mode->dmPelsHeight == 0;
1723 /***********************************************************************
1724 * NtUserChangeDisplaySettingsExW (win32u.@)
1726 LONG WINAPI NtUserChangeDisplaySettings( UNICODE_STRING *devname, DEVMODEW *devmode, HWND hwnd,
1727 DWORD flags, void *lparam )
1729 WCHAR device_name[CCHDEVICENAME];
1730 struct adapter *adapter;
1731 BOOL def_mode = TRUE;
1732 DEVMODEW dm;
1733 LONG ret;
1735 TRACE( "%s %p %p %#x %p\n", debugstr_us(devname), devmode, hwnd, flags, lparam );
1736 TRACE( "flags=%s\n", _CDS_flags(flags) );
1738 if ((!devname || !devname->Length) && !devmode)
1740 ret = user_driver->pChangeDisplaySettingsEx( NULL, NULL, hwnd, flags, lparam );
1741 if (ret != DISP_CHANGE_SUCCESSFUL)
1742 ERR( "Restoring all displays to their registry settings returned %d.\n", ret );
1743 return ret;
1746 if (!lock_display_devices()) return DISP_CHANGE_FAILED;
1747 if ((adapter = find_adapter( devname ))) lstrcpyW( device_name, adapter->dev.device_name );
1748 unlock_display_devices();
1749 if (!adapter)
1751 WARN( "Invalid device name %s.\n", debugstr_us(devname) );
1752 return DISP_CHANGE_BADPARAM;
1755 if (devmode)
1757 trace_devmode( devmode );
1759 if (devmode->dmSize < FIELD_OFFSET(DEVMODEW, dmICMMethod))
1760 return DISP_CHANGE_BADMODE;
1762 if (is_detached_mode(devmode) ||
1763 ((devmode->dmFields & DM_BITSPERPEL) && devmode->dmBitsPerPel) ||
1764 ((devmode->dmFields & DM_PELSWIDTH) && devmode->dmPelsWidth) ||
1765 ((devmode->dmFields & DM_PELSHEIGHT) && devmode->dmPelsHeight) ||
1766 ((devmode->dmFields & DM_DISPLAYFREQUENCY) && devmode->dmDisplayFrequency))
1767 def_mode = FALSE;
1770 if (def_mode)
1772 memset( &dm, 0, sizeof(dm) );
1773 dm.dmSize = sizeof(dm);
1774 if (!NtUserEnumDisplaySettings( devname, ENUM_REGISTRY_SETTINGS, &dm, 0 ))
1776 ERR( "Default mode not found!\n" );
1777 return DISP_CHANGE_BADMODE;
1780 TRACE( "Return to original display mode\n" );
1781 devmode = &dm;
1784 if ((devmode->dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != (DM_PELSWIDTH | DM_PELSHEIGHT))
1786 WARN( "devmode doesn't specify the resolution: %#x\n", devmode->dmFields );
1787 return DISP_CHANGE_BADMODE;
1790 if (!is_detached_mode(devmode) && (!devmode->dmPelsWidth || !devmode->dmPelsHeight))
1792 memset(&dm, 0, sizeof(dm));
1793 dm.dmSize = sizeof(dm);
1794 if (!NtUserEnumDisplaySettings( devname, ENUM_CURRENT_SETTINGS, &dm, 0 ))
1796 ERR( "Current mode not found!\n" );
1797 return DISP_CHANGE_BADMODE;
1800 if (!devmode->dmPelsWidth)
1801 devmode->dmPelsWidth = dm.dmPelsWidth;
1802 if (!devmode->dmPelsHeight)
1803 devmode->dmPelsHeight = dm.dmPelsHeight;
1806 ret = user_driver->pChangeDisplaySettingsEx( device_name, devmode, hwnd, flags, lparam );
1807 if (ret != DISP_CHANGE_SUCCESSFUL)
1808 ERR( "Changing %s display settings returned %d.\n", debugstr_us(devname), ret );
1809 return ret;
1812 /***********************************************************************
1813 * NtUserEnumDisplaySettings (win32u.@)
1815 BOOL WINAPI NtUserEnumDisplaySettings( UNICODE_STRING *device, DWORD mode,
1816 DEVMODEW *dev_mode, DWORD flags )
1818 WCHAR device_name[CCHDEVICENAME];
1819 struct adapter *adapter;
1820 BOOL ret;
1822 TRACE( "%s %#x %p %#x\n", debugstr_us(device), mode, dev_mode, flags );
1824 if (!lock_display_devices()) return FALSE;
1825 if ((adapter = find_adapter( device ))) lstrcpyW( device_name, adapter->dev.device_name );
1826 unlock_display_devices();
1827 if (!adapter)
1829 WARN( "Invalid device name %s.\n", debugstr_us(device) );
1830 return FALSE;
1833 ret = user_driver->pEnumDisplaySettingsEx( device_name, mode, dev_mode, flags );
1834 if (ret)
1835 TRACE( "device:%s mode index:%#x position:(%d,%d) resolution:%ux%u frequency:%uHz "
1836 "depth:%ubits orientation:%#x.\n", debugstr_w(device_name), mode,
1837 dev_mode->dmPosition.x, dev_mode->dmPosition.y, dev_mode->dmPelsWidth,
1838 dev_mode->dmPelsHeight, dev_mode->dmDisplayFrequency, dev_mode->dmBitsPerPel,
1839 dev_mode->dmDisplayOrientation );
1840 else
1841 WARN( "Failed to query %s display settings.\n", wine_dbgstr_w(device_name) );
1842 return ret;
1845 struct monitor_enum_info
1847 HANDLE handle;
1848 RECT rect;
1851 static unsigned int active_monitor_count(void)
1853 struct monitor *monitor;
1854 unsigned int count = 0;
1856 LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry)
1858 if ((monitor->dev.state_flags & DISPLAY_DEVICE_ACTIVE)) count++;
1860 return count;
1863 /***********************************************************************
1864 * NtUserEnumDisplayMonitors (win32u.@)
1866 BOOL WINAPI NtUserEnumDisplayMonitors( HDC hdc, RECT *rect, MONITORENUMPROC proc, LPARAM lparam )
1868 struct monitor_enum_info enum_buf[8], *enum_info = enum_buf;
1869 struct enum_display_monitor_params params;
1870 struct monitor *monitor;
1871 unsigned int count = 0, i;
1872 POINT origin;
1873 RECT limit;
1874 BOOL ret = TRUE;
1876 if (hdc)
1878 DC *dc;
1879 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
1880 origin.x = dc->attr->vis_rect.left;
1881 origin.y = dc->attr->vis_rect.top;
1882 release_dc_ptr( dc );
1883 if (NtGdiGetAppClipBox( hdc, &limit ) == ERROR) return FALSE;
1885 else
1887 origin.x = origin.y = 0;
1888 limit.left = limit.top = INT_MIN;
1889 limit.right = limit.bottom = INT_MAX;
1891 if (rect && !intersect_rect( &limit, &limit, rect )) return TRUE;
1893 if (!lock_display_devices()) return FALSE;
1895 count = list_count( &monitors );
1896 if (!count || (count > ARRAYSIZE(enum_buf) &&
1897 !(enum_info = malloc( count * sizeof(*enum_info) ))))
1899 unlock_display_devices();
1900 return FALSE;
1903 count = 0;
1904 LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry)
1906 RECT monrect;
1908 if (!(monitor->dev.state_flags & DISPLAY_DEVICE_ACTIVE)) continue;
1910 monrect = map_dpi_rect( monitor->rc_monitor, get_monitor_dpi( monitor->handle ),
1911 get_thread_dpi() );
1912 offset_rect( &monrect, -origin.x, -origin.y );
1913 if (!intersect_rect( &monrect, &monrect, &limit )) continue;
1915 enum_info[count].handle = monitor->handle;
1916 enum_info[count].rect = monrect;
1917 count++;
1920 unlock_display_devices();
1922 params.proc = proc;
1923 params.hdc = hdc;
1924 params.lparam = lparam;
1925 for (i = 0; i < count; i++)
1927 params.monitor = enum_info[i].handle;
1928 params.rect = enum_info[i].rect;
1929 if (!user32_call( NtUserCallEnumDisplayMonitor, &params, sizeof(params) ))
1931 ret = FALSE;
1932 break;
1935 if (enum_info != enum_buf) free( enum_info );
1936 return ret;
1939 static BOOL get_monitor_info( HMONITOR handle, MONITORINFO *info )
1941 struct monitor *monitor;
1942 UINT dpi_from, dpi_to;
1944 if (info->cbSize != sizeof(MONITORINFOEXW) && info->cbSize != sizeof(MONITORINFO)) return FALSE;
1946 if (!lock_display_devices()) return FALSE;
1948 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
1950 if (monitor->handle != handle) continue;
1951 if (!(monitor->dev.state_flags & DISPLAY_DEVICE_ACTIVE)) break;
1953 /* FIXME: map dpi */
1954 info->rcMonitor = monitor->rc_monitor;
1955 info->rcWork = monitor->rc_work;
1956 info->dwFlags = monitor->flags;
1957 if (info->cbSize >= sizeof(MONITORINFOEXW))
1959 if (monitor->adapter)
1960 lstrcpyW( ((MONITORINFOEXW *)info)->szDevice, monitor->adapter->dev.device_name );
1961 else
1962 asciiz_to_unicode( ((MONITORINFOEXW *)info)->szDevice, "WinDisc" );
1964 unlock_display_devices();
1966 if ((dpi_to = get_thread_dpi()))
1968 dpi_from = get_monitor_dpi( handle );
1969 info->rcMonitor = map_dpi_rect( info->rcMonitor, dpi_from, dpi_to );
1970 info->rcWork = map_dpi_rect( info->rcWork, dpi_from, dpi_to );
1972 TRACE( "flags %04x, monitor %s, work %s\n", info->dwFlags,
1973 wine_dbgstr_rect(&info->rcMonitor), wine_dbgstr_rect(&info->rcWork));
1974 return TRUE;
1977 unlock_display_devices();
1978 WARN( "invalid handle %p\n", handle );
1979 SetLastError( ERROR_INVALID_MONITOR_HANDLE );
1980 return FALSE;
1983 HMONITOR monitor_from_rect( const RECT *rect, DWORD flags, UINT dpi )
1985 HMONITOR primary = 0, nearest = 0, ret = 0;
1986 UINT max_area = 0, min_distance = ~0u;
1987 struct monitor *monitor;
1988 RECT r;
1990 r = map_dpi_rect( *rect, dpi, system_dpi );
1991 if (is_rect_empty( &r ))
1993 r.right = r.left + 1;
1994 r.bottom = r.top + 1;
1997 if (!lock_display_devices()) return 0;
1999 LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry)
2001 RECT intersect;
2002 RECT monitor_rect = map_dpi_rect( monitor->rc_monitor, get_monitor_dpi( monitor->handle ),
2003 system_dpi );
2005 if (intersect_rect( &intersect, &monitor_rect, &r ))
2007 /* check for larger intersecting area */
2008 UINT area = (intersect.right - intersect.left) * (intersect.bottom - intersect.top);
2009 if (area > max_area)
2011 max_area = area;
2012 ret = monitor->handle;
2015 else if (!max_area) /* if not intersecting, check for min distance */
2017 UINT distance;
2018 UINT x, y;
2020 if (r.right <= monitor_rect.left) x = monitor_rect.left - r.right;
2021 else if (monitor_rect.right <= r.left) x = r.left - monitor_rect.right;
2022 else x = 0;
2023 if (r.bottom <= monitor_rect.top) y = monitor_rect.top - r.bottom;
2024 else if (monitor_rect.bottom <= r.top) y = r.top - monitor_rect.bottom;
2025 else y = 0;
2026 distance = x * x + y * y;
2027 if (distance < min_distance)
2029 min_distance = distance;
2030 nearest = monitor->handle;
2034 if (monitor->flags & MONITORINFOF_PRIMARY) primary = monitor->handle;
2037 unlock_display_devices();
2039 if (!ret)
2041 if (flags & MONITOR_DEFAULTTOPRIMARY) ret = primary;
2042 else if (flags & MONITOR_DEFAULTTONEAREST) ret = nearest;
2045 TRACE( "%s flags %x returning %p\n", wine_dbgstr_rect(rect), flags, ret );
2046 return ret;
2049 HMONITOR monitor_from_point( POINT pt, DWORD flags, UINT dpi )
2051 RECT rect;
2052 SetRect( &rect, pt.x, pt.y, pt.x + 1, pt.y + 1 );
2053 return monitor_from_rect( &rect, flags, dpi );
2056 /***********************************************************************
2057 * NtUserGetSystemDpiForProcess (win32u.@)
2059 ULONG WINAPI NtUserGetSystemDpiForProcess( HANDLE process )
2061 if (process && process != GetCurrentProcess())
2063 FIXME( "not supported on other process %p\n", process );
2064 return 0;
2067 return system_dpi;
2070 /***********************************************************************
2071 * NtUserGetDpiForMonitor (win32u.@)
2073 BOOL WINAPI NtUserGetDpiForMonitor( HMONITOR monitor, UINT type, UINT *x, UINT *y )
2075 if (type > 2)
2077 SetLastError( ERROR_BAD_ARGUMENTS );
2078 return FALSE;
2080 if (!x || !y)
2082 SetLastError( ERROR_INVALID_ADDRESS );
2083 return FALSE;
2085 switch (get_thread_dpi_awareness())
2087 case DPI_AWARENESS_UNAWARE: *x = *y = USER_DEFAULT_SCREEN_DPI; break;
2088 case DPI_AWARENESS_SYSTEM_AWARE: *x = *y = system_dpi; break;
2089 default: *x = *y = get_monitor_dpi( monitor ); break;
2091 return TRUE;
2094 /* retrieve the cached base keys for a given entry */
2095 static BOOL get_base_keys( enum parameter_key index, HKEY *base_key, HKEY *volatile_key )
2097 static HKEY base_keys[NB_PARAM_KEYS];
2098 static HKEY volatile_keys[NB_PARAM_KEYS];
2099 WCHAR bufferW[128];
2100 HKEY key;
2102 if (!base_keys[index] && base_key)
2104 if (!(key = reg_create_key( hkcu_key, bufferW,
2105 asciiz_to_unicode( bufferW, parameter_key_names[index] ) - sizeof(WCHAR),
2106 0, NULL )))
2107 return FALSE;
2108 if (InterlockedCompareExchangePointer( (void **)&base_keys[index], key, 0 ))
2109 NtClose( key );
2111 if (!volatile_keys[index] && volatile_key)
2113 if (!(key = reg_create_key( volatile_base_key, bufferW,
2114 asciiz_to_unicode( bufferW, parameter_key_names[index] ) - sizeof(WCHAR),
2115 REG_OPTION_VOLATILE, NULL )))
2116 return FALSE;
2117 if (InterlockedCompareExchangePointer( (void **)&volatile_keys[index], key, 0 ))
2118 NtClose( key );
2120 if (base_key) *base_key = base_keys[index];
2121 if (volatile_key) *volatile_key = volatile_keys[index];
2122 return TRUE;
2125 /* load a value to a registry entry */
2126 static DWORD load_entry( struct sysparam_entry *entry, void *data, DWORD size )
2128 char buffer[4096];
2129 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
2130 DWORD count;
2131 HKEY base_key, volatile_key;
2133 if (!get_base_keys( entry->base_key, &base_key, &volatile_key )) return FALSE;
2135 if (!(count = query_reg_ascii_value( volatile_key, entry->regval, value, sizeof(buffer) )))
2136 count = query_reg_ascii_value( base_key, entry->regval, value, sizeof(buffer) );
2137 if (count > size)
2139 count = size;
2140 /* make sure strings are null-terminated */
2141 if (value->Type == REG_SZ) ((WCHAR *)value->Data)[count / sizeof(WCHAR) - 1] = 0;
2143 if (count) memcpy( data, value->Data, count );
2144 entry->loaded = TRUE;
2145 return count;
2148 /* save a value to a registry entry */
2149 static BOOL save_entry( const struct sysparam_entry *entry, const void *data, DWORD size,
2150 DWORD type, UINT flags )
2152 HKEY base_key, volatile_key;
2153 WCHAR nameW[64];
2155 asciiz_to_unicode( nameW, entry->regval );
2156 if (flags & SPIF_UPDATEINIFILE)
2158 if (!get_base_keys( entry->base_key, &base_key, &volatile_key )) return FALSE;
2159 if (!set_reg_value( base_key, nameW, type, data, size )) return FALSE;
2160 reg_delete_value( volatile_key, nameW );
2162 if (entry->mirror && get_base_keys( entry->mirror_key, &base_key, NULL ))
2164 asciiz_to_unicode( nameW, entry->mirror );
2165 set_reg_value( base_key, nameW, type, data, size );
2168 else
2170 if (!get_base_keys( entry->base_key, NULL, &volatile_key )) return FALSE;
2171 if (!set_reg_value( volatile_key, nameW, type, data, size )) return FALSE;
2173 return TRUE;
2176 /* save a string value to a registry entry */
2177 static BOOL save_entry_string( const struct sysparam_entry *entry, const WCHAR *str, UINT flags )
2179 return save_entry( entry, str, (lstrlenW(str) + 1) * sizeof(WCHAR), REG_SZ, flags );
2182 /* initialize an entry in the registry if missing */
2183 static BOOL init_entry( struct sysparam_entry *entry, const void *data, DWORD size, DWORD type )
2185 KEY_VALUE_PARTIAL_INFORMATION value;
2186 UNICODE_STRING name;
2187 WCHAR nameW[64];
2188 HKEY base_key;
2189 DWORD count;
2190 NTSTATUS status;
2192 if (!get_base_keys( entry->base_key, &base_key, NULL )) return FALSE;
2194 name.Buffer = nameW;
2195 name.MaximumLength = asciiz_to_unicode( nameW, entry->regval );
2196 name.Length = name.MaximumLength - sizeof(WCHAR);
2197 status = NtQueryValueKey( base_key, &name, KeyValuePartialInformation,
2198 &value, sizeof(value), &count );
2199 if (!status || status == STATUS_BUFFER_OVERFLOW) return TRUE;
2201 if (!set_reg_value( base_key, nameW, type, data, size )) return FALSE;
2202 if (entry->mirror && get_base_keys( entry->mirror_key, &base_key, NULL ))
2204 asciiz_to_unicode( nameW, entry->mirror );
2205 set_reg_value( base_key, nameW, type, data, size );
2207 entry->loaded = TRUE;
2208 return TRUE;
2211 /* initialize a string value in the registry if missing */
2212 static BOOL init_entry_string( struct sysparam_entry *entry, const WCHAR *str )
2214 return init_entry( entry, str, (lstrlenW(str) + 1) * sizeof(WCHAR), REG_SZ );
2217 /* set an int parameter in the registry */
2218 static BOOL set_int_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2220 WCHAR bufW[32];
2221 char buf[32];
2223 sprintf( buf, "%d", int_param );
2224 asciiz_to_unicode( bufW, buf );
2225 if (!save_entry_string( &entry->hdr, bufW, flags )) return FALSE;
2226 entry->uint.val = int_param;
2227 entry->hdr.loaded = TRUE;
2228 return TRUE;
2231 /* initialize an int parameter */
2232 static BOOL init_int_entry( union sysparam_all_entry *entry )
2234 WCHAR bufW[32];
2235 char buf[32];
2237 sprintf( buf, "%d", entry->uint.val );
2238 asciiz_to_unicode( bufW, buf );
2239 return init_entry_string( &entry->hdr, bufW );
2242 /* load a uint parameter from the registry */
2243 static BOOL get_uint_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2245 if (!ptr_param) return FALSE;
2247 if (!entry->hdr.loaded)
2249 WCHAR buf[32];
2250 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->uint.val = wcstol( buf, NULL, 10 );
2252 *(UINT *)ptr_param = entry->uint.val;
2253 return TRUE;
2256 /* set a uint parameter in the registry */
2257 static BOOL set_uint_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2259 WCHAR bufW[32];
2260 char buf[32];
2262 sprintf( buf, "%u", int_param );
2263 asciiz_to_unicode( bufW, buf );
2264 if (!save_entry_string( &entry->hdr, bufW, flags )) return FALSE;
2265 entry->uint.val = int_param;
2266 entry->hdr.loaded = TRUE;
2267 return TRUE;
2270 /* initialize a uint parameter */
2271 static BOOL init_uint_entry( union sysparam_all_entry *entry )
2273 WCHAR bufW[32];
2274 char buf[32];
2276 sprintf( buf, "%u", entry->uint.val );
2277 asciiz_to_unicode( bufW, buf );
2278 return init_entry_string( &entry->hdr, bufW );
2281 /* load a twips parameter from the registry */
2282 static BOOL get_twips_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2284 int val;
2286 if (!ptr_param) return FALSE;
2288 if (!entry->hdr.loaded)
2290 WCHAR buf[32];
2291 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->uint.val = wcstol( buf, NULL, 10 );
2294 /* Dimensions are quoted as being "twips" values if negative and pixels if positive.
2295 * One inch is 1440 twips.
2296 * See for example
2297 * Technical Reference to the Windows 2000 Registry ->
2298 * HKEY_CURRENT_USER -> Control Panel -> Desktop -> WindowMetrics
2300 val = entry->uint.val;
2301 if (val < 0)
2302 val = muldiv( -val, dpi, 1440 );
2303 else
2304 val = map_to_dpi( val, dpi );
2306 *(int *)ptr_param = val;
2307 return TRUE;
2310 /* set a twips parameter in the registry */
2311 static BOOL set_twips_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2313 int val = int_param;
2314 if (val > 0) val = map_from_system_dpi( val );
2315 return set_int_entry( entry, val, ptr_param, flags );
2318 /* load a bool parameter from the registry */
2319 static BOOL get_bool_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2321 if (!ptr_param) return FALSE;
2323 if (!entry->hdr.loaded)
2325 WCHAR buf[32];
2326 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->bool.val = wcstol( buf, NULL, 10 ) != 0;
2328 *(UINT *)ptr_param = entry->bool.val;
2329 return TRUE;
2332 /* set a bool parameter in the registry */
2333 static BOOL set_bool_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2335 WCHAR buf[] = { int_param ? '1' : '0', 0 };
2337 if (!save_entry_string( &entry->hdr, buf, flags )) return FALSE;
2338 entry->bool.val = int_param != 0;
2339 entry->hdr.loaded = TRUE;
2340 return TRUE;
2343 /* initialize a bool parameter */
2344 static BOOL init_bool_entry( union sysparam_all_entry *entry )
2346 WCHAR buf[] = { entry->bool.val ? '1' : '0', 0 };
2348 return init_entry_string( &entry->hdr, buf );
2351 /* load a bool parameter using Yes/No strings from the registry */
2352 static BOOL get_yesno_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2354 if (!ptr_param) return FALSE;
2356 if (!entry->hdr.loaded)
2358 WCHAR buf[32];
2359 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->bool.val = !wcsicmp( yesW, buf );
2361 *(UINT *)ptr_param = entry->bool.val;
2362 return TRUE;
2365 /* set a bool parameter using Yes/No strings from the registry */
2366 static BOOL set_yesno_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2368 const WCHAR *str = int_param ? yesW : noW;
2370 if (!save_entry_string( &entry->hdr, str, flags )) return FALSE;
2371 entry->bool.val = int_param != 0;
2372 entry->hdr.loaded = TRUE;
2373 return TRUE;
2376 /* initialize a bool parameter using Yes/No strings */
2377 static BOOL init_yesno_entry( union sysparam_all_entry *entry )
2379 return init_entry_string( &entry->hdr, entry->bool.val ? yesW : noW );
2382 /* load a dword (binary) parameter from the registry */
2383 static BOOL get_dword_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2385 if (!ptr_param) return FALSE;
2387 if (!entry->hdr.loaded)
2389 DWORD val;
2390 if (load_entry( &entry->hdr, &val, sizeof(val) ) == sizeof(DWORD)) entry->dword.val = val;
2392 *(DWORD *)ptr_param = entry->dword.val;
2393 return TRUE;
2396 /* set a dword (binary) parameter in the registry */
2397 static BOOL set_dword_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2399 DWORD val = PtrToUlong( ptr_param );
2401 if (!save_entry( &entry->hdr, &val, sizeof(val), REG_DWORD, flags )) return FALSE;
2402 entry->dword.val = val;
2403 entry->hdr.loaded = TRUE;
2404 return TRUE;
2407 /* initialize a dword parameter */
2408 static BOOL init_dword_entry( union sysparam_all_entry *entry )
2410 return init_entry( &entry->hdr, &entry->dword.val, sizeof(entry->dword.val), REG_DWORD );
2413 /* load an RGB parameter from the registry */
2414 static BOOL get_rgb_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2416 if (!ptr_param) return FALSE;
2418 if (!entry->hdr.loaded)
2420 WCHAR buf[32];
2422 if (load_entry( &entry->hdr, buf, sizeof(buf) ))
2424 DWORD r, g, b;
2425 WCHAR *end, *str = buf;
2427 r = wcstoul( str, &end, 10 );
2428 if (end == str || !*end) goto done;
2429 str = end + 1;
2430 g = wcstoul( str, &end, 10 );
2431 if (end == str || !*end) goto done;
2432 str = end + 1;
2433 b = wcstoul( str, &end, 10 );
2434 if (end == str) goto done;
2435 if (r > 255 || g > 255 || b > 255) goto done;
2436 entry->rgb.val = RGB( r, g, b );
2439 done:
2440 *(COLORREF *)ptr_param = entry->rgb.val;
2441 return TRUE;
2444 /* set an RGB parameter in the registry */
2445 static BOOL set_rgb_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2447 WCHAR bufW[32];
2448 char buf[32];
2449 HBRUSH brush;
2450 HPEN pen;
2452 sprintf( buf, "%u %u %u", GetRValue(int_param), GetGValue(int_param), GetBValue(int_param) );
2453 asciiz_to_unicode( bufW, buf );
2454 if (!save_entry_string( &entry->hdr, bufW, flags )) return FALSE;
2455 entry->rgb.val = int_param;
2456 entry->hdr.loaded = TRUE;
2457 if ((brush = InterlockedExchangePointer( (void **)&entry->rgb.brush, 0 )))
2459 make_gdi_object_system( brush, FALSE );
2460 NtGdiDeleteObjectApp( brush );
2462 if ((pen = InterlockedExchangePointer( (void **)&entry->rgb.pen, 0 )))
2464 make_gdi_object_system( pen, FALSE );
2465 NtGdiDeleteObjectApp( pen );
2467 return TRUE;
2470 /* initialize an RGB parameter */
2471 static BOOL init_rgb_entry( union sysparam_all_entry *entry )
2473 WCHAR bufW[32];
2474 char buf[32];
2476 sprintf( buf, "%u %u %u", GetRValue(entry->rgb.val), GetGValue(entry->rgb.val),
2477 GetBValue(entry->rgb.val) );
2478 asciiz_to_unicode( bufW, buf );
2479 return init_entry_string( &entry->hdr, bufW );
2482 /* get a path parameter in the registry */
2483 static BOOL get_path_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2485 if (!ptr_param) return FALSE;
2487 if (!entry->hdr.loaded)
2489 WCHAR buffer[MAX_PATH];
2491 if (load_entry( &entry->hdr, buffer, sizeof(buffer) ))
2492 lstrcpynW( entry->path.path, buffer, MAX_PATH );
2494 lstrcpynW( ptr_param, entry->path.path, int_param );
2495 return TRUE;
2498 /* set a path parameter in the registry */
2499 static BOOL set_path_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2501 WCHAR buffer[MAX_PATH];
2502 BOOL ret;
2504 lstrcpynW( buffer, ptr_param, MAX_PATH );
2505 ret = save_entry_string( &entry->hdr, buffer, flags );
2506 if (ret)
2508 lstrcpyW( entry->path.path, buffer );
2509 entry->hdr.loaded = TRUE;
2511 return ret;
2514 /* initialize a path parameter */
2515 static BOOL init_path_entry( union sysparam_all_entry *entry )
2517 return init_entry_string( &entry->hdr, entry->path.path );
2520 /* get a binary parameter in the registry */
2521 static BOOL get_binary_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2523 if (!ptr_param) return FALSE;
2525 if (!entry->hdr.loaded)
2527 void *buffer = malloc( entry->bin.size );
2528 DWORD len = load_entry( &entry->hdr, buffer, entry->bin.size );
2530 if (len)
2532 memcpy( entry->bin.ptr, buffer, entry->bin.size );
2533 memset( (char *)entry->bin.ptr + len, 0, entry->bin.size - len );
2535 free( buffer );
2537 memcpy( ptr_param, entry->bin.ptr, min( int_param, entry->bin.size ) );
2538 return TRUE;
2541 /* set a binary parameter in the registry */
2542 static BOOL set_binary_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2544 BOOL ret;
2545 void *buffer = malloc( entry->bin.size );
2547 memcpy( buffer, entry->bin.ptr, entry->bin.size );
2548 memcpy( buffer, ptr_param, min( int_param, entry->bin.size ));
2549 ret = save_entry( &entry->hdr, buffer, entry->bin.size, REG_BINARY, flags );
2550 if (ret)
2552 memcpy( entry->bin.ptr, buffer, entry->bin.size );
2553 entry->hdr.loaded = TRUE;
2555 free( buffer );
2556 return ret;
2559 /* initialize a binary parameter */
2560 static BOOL init_binary_entry( union sysparam_all_entry *entry )
2562 return init_entry( &entry->hdr, entry->bin.ptr, entry->bin.size, REG_BINARY );
2565 static void logfont16to32( const LOGFONT16 *font16, LPLOGFONTW font32 )
2567 font32->lfHeight = font16->lfHeight;
2568 font32->lfWidth = font16->lfWidth;
2569 font32->lfEscapement = font16->lfEscapement;
2570 font32->lfOrientation = font16->lfOrientation;
2571 font32->lfWeight = font16->lfWeight;
2572 font32->lfItalic = font16->lfItalic;
2573 font32->lfUnderline = font16->lfUnderline;
2574 font32->lfStrikeOut = font16->lfStrikeOut;
2575 font32->lfCharSet = font16->lfCharSet;
2576 font32->lfOutPrecision = font16->lfOutPrecision;
2577 font32->lfClipPrecision = font16->lfClipPrecision;
2578 font32->lfQuality = font16->lfQuality;
2579 font32->lfPitchAndFamily = font16->lfPitchAndFamily;
2580 win32u_mbtowc( NULL, font32->lfFaceName, LF_FACESIZE, font16->lfFaceName,
2581 strlen( font16->lfFaceName ));
2582 font32->lfFaceName[LF_FACESIZE-1] = 0;
2585 static void get_real_fontname( LOGFONTW *lf, WCHAR fullname[LF_FACESIZE] )
2587 struct font_enum_entry enum_entry;
2588 ULONG count = sizeof(enum_entry);
2589 HDC hdc;
2591 hdc = get_display_dc();
2592 NtGdiEnumFonts( hdc, 0, 0, lstrlenW( lf->lfFaceName ), lf->lfFaceName, lf->lfCharSet,
2593 &count, &enum_entry );
2594 release_display_dc( hdc );
2596 if (count)
2597 lstrcpyW( fullname, enum_entry.lf.elfFullName );
2598 else
2599 lstrcpyW( fullname, lf->lfFaceName );
2602 /* get text metrics and/or "average" char width of the specified logfont
2603 * for the specified dc */
2604 static void get_text_metr_size( HDC hdc, LOGFONTW *plf, TEXTMETRICW * ptm, UINT *psz)
2606 ENUMLOGFONTEXDVW exdv = { .elfEnumLogfontEx.elfLogFont = *plf };
2607 HFONT hfont, hfontsav;
2608 TEXTMETRICW tm;
2609 if (!ptm) ptm = &tm;
2610 hfont = NtGdiHfontCreate( &exdv, sizeof(exdv), 0, 0, NULL );
2611 if (!hfont || !(hfontsav = NtGdiSelectFont( hdc, hfont )))
2613 ptm->tmHeight = -1;
2614 if (psz) *psz = 10;
2615 if (hfont) NtGdiDeleteObjectApp( hfont );
2616 return;
2618 NtGdiGetTextMetricsW( hdc, ptm, 0 );
2619 if (psz)
2621 SIZE sz;
2622 static const WCHAR abcdW[] =
2623 {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
2624 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
2625 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
2626 if (NtGdiGetTextExtentExW( hdc, abcdW, ARRAYSIZE(abcdW), 0, NULL, NULL, &sz, 0 ))
2627 *psz = (sz.cx / 26 + 1) / 2;
2628 else *psz = 10;
2630 NtGdiSelectFont( hdc, hfontsav );
2631 NtGdiDeleteObjectApp( hfont );
2634 /* adjust some of the raw values found in the registry */
2635 static void normalize_nonclientmetrics( NONCLIENTMETRICSW *pncm)
2637 TEXTMETRICW tm;
2638 HDC hdc = get_display_dc();
2640 if( pncm->iBorderWidth < 1) pncm->iBorderWidth = 1;
2641 if( pncm->iCaptionWidth < 8) pncm->iCaptionWidth = 8;
2642 if( pncm->iScrollWidth < 8) pncm->iScrollWidth = 8;
2643 if( pncm->iScrollHeight < 8) pncm->iScrollHeight = 8;
2645 /* adjust some heights to the corresponding font */
2646 get_text_metr_size( hdc, &pncm->lfMenuFont, &tm, NULL);
2647 pncm->iMenuHeight = max( pncm->iMenuHeight, 2 + tm.tmHeight + tm.tmExternalLeading );
2648 get_text_metr_size( hdc, &pncm->lfCaptionFont, &tm, NULL);
2649 pncm->iCaptionHeight = max( pncm->iCaptionHeight, 2 + tm.tmHeight);
2650 get_text_metr_size( hdc, &pncm->lfSmCaptionFont, &tm, NULL);
2651 pncm->iSmCaptionHeight = max( pncm->iSmCaptionHeight, 2 + tm.tmHeight);
2652 release_display_dc( hdc );
2655 /* load a font (binary) parameter from the registry */
2656 static BOOL get_font_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2658 LOGFONTW font;
2660 if (!ptr_param) return FALSE;
2662 if (!entry->hdr.loaded)
2664 switch (load_entry( &entry->hdr, &font, sizeof(font) ))
2666 case sizeof(font):
2667 if (font.lfHeight > 0) /* positive height value means points ( inch/72 ) */
2668 font.lfHeight = -muldiv( font.lfHeight, USER_DEFAULT_SCREEN_DPI, 72 );
2669 entry->font.val = font;
2670 break;
2671 case sizeof(LOGFONT16): /* win9x-winME format */
2672 logfont16to32( (LOGFONT16 *)&font, &entry->font.val );
2673 if (entry->font.val.lfHeight > 0)
2674 entry->font.val.lfHeight = -muldiv( entry->font.val.lfHeight, USER_DEFAULT_SCREEN_DPI, 72 );
2675 break;
2676 default:
2677 WARN( "Unknown format in key %s value %s\n",
2678 debugstr_a( parameter_key_names[entry->hdr.base_key] ),
2679 debugstr_a( entry->hdr.regval ));
2680 /* fall through */
2681 case 0: /* use the default GUI font */
2682 NtGdiExtGetObjectW( get_stock_object( DEFAULT_GUI_FONT ), sizeof(font), &font );
2683 font.lfHeight = map_from_system_dpi( font.lfHeight );
2684 font.lfWeight = entry->font.weight;
2685 entry->font.val = font;
2686 break;
2688 get_real_fontname( &entry->font.val, entry->font.fullname );
2689 entry->hdr.loaded = TRUE;
2691 font = entry->font.val;
2692 font.lfHeight = map_to_dpi( font.lfHeight, dpi );
2693 lstrcpyW( font.lfFaceName, entry->font.fullname );
2694 *(LOGFONTW *)ptr_param = font;
2695 return TRUE;
2698 /* set a font (binary) parameter in the registry */
2699 static BOOL set_font_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2701 LOGFONTW font;
2702 WCHAR *ptr;
2704 memcpy( &font, ptr_param, sizeof(font) );
2705 /* zero pad the end of lfFaceName so we don't save uninitialised data */
2706 for (ptr = font.lfFaceName; ptr < font.lfFaceName + LF_FACESIZE && *ptr; ptr++);
2707 if (ptr < font.lfFaceName + LF_FACESIZE)
2708 memset( ptr, 0, (font.lfFaceName + LF_FACESIZE - ptr) * sizeof(WCHAR) );
2709 if (font.lfHeight < 0) font.lfHeight = map_from_system_dpi( font.lfHeight );
2711 if (!save_entry( &entry->hdr, &font, sizeof(font), REG_BINARY, flags )) return FALSE;
2712 entry->font.val = font;
2713 get_real_fontname( &entry->font.val, entry->font.fullname );
2714 entry->hdr.loaded = TRUE;
2715 return TRUE;
2718 /* initialize a font (binary) parameter */
2719 static BOOL init_font_entry( union sysparam_all_entry *entry )
2721 NtGdiExtGetObjectW( get_stock_object( DEFAULT_GUI_FONT ), sizeof(entry->font.val), &entry->font.val );
2722 entry->font.val.lfHeight = map_from_system_dpi( entry->font.val.lfHeight );
2723 entry->font.val.lfWeight = entry->font.weight;
2724 get_real_fontname( &entry->font.val, entry->font.fullname );
2725 return init_entry( &entry->hdr, &entry->font.val, sizeof(entry->font.val), REG_BINARY );
2728 /* get a user pref parameter in the registry */
2729 static BOOL get_userpref_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
2731 union sysparam_all_entry *parent_entry = (union sysparam_all_entry *)entry->pref.parent;
2732 BYTE prefs[8];
2734 if (!ptr_param) return FALSE;
2736 if (!parent_entry->hdr.get( parent_entry, sizeof(prefs), prefs, dpi )) return FALSE;
2737 *(BOOL *)ptr_param = (prefs[entry->pref.offset] & entry->pref.mask) != 0;
2738 return TRUE;
2741 /* set a user pref parameter in the registry */
2742 static BOOL set_userpref_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
2744 union sysparam_all_entry *parent_entry = (union sysparam_all_entry *)entry->pref.parent;
2745 BYTE prefs[8];
2747 parent_entry->hdr.loaded = FALSE; /* force loading it again */
2748 if (!parent_entry->hdr.get( parent_entry, sizeof(prefs), prefs, get_system_dpi() )) return FALSE;
2750 if (PtrToUlong( ptr_param )) prefs[entry->pref.offset] |= entry->pref.mask;
2751 else prefs[entry->pref.offset] &= ~entry->pref.mask;
2753 return parent_entry->hdr.set( parent_entry, sizeof(prefs), prefs, flags );
2756 static BOOL get_entry_dpi( void *ptr, UINT int_param, void *ptr_param, UINT dpi )
2758 union sysparam_all_entry *entry = ptr;
2759 return entry->hdr.get( entry, int_param, ptr_param, dpi );
2762 static BOOL get_entry( void *ptr, UINT int_param, void *ptr_param )
2764 return get_entry_dpi( ptr, int_param, ptr_param, get_system_dpi() );
2767 static BOOL set_entry( void *ptr, UINT int_param, void *ptr_param, UINT flags )
2769 union sysparam_all_entry *entry = ptr;
2770 return entry->hdr.set( entry, int_param, ptr_param, flags );
2773 #define UINT_ENTRY(name,val,base,reg) \
2774 struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_uint_entry, init_uint_entry, \
2775 base, reg }, (val) }
2777 #define UINT_ENTRY_MIRROR(name,val,base,reg,mirror_base) \
2778 struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_uint_entry, init_uint_entry, \
2779 base, reg, mirror_base, reg }, (val) }
2781 #define INT_ENTRY(name,val,base,reg) \
2782 struct sysparam_uint_entry entry_##name = { { get_uint_entry, set_int_entry, init_int_entry, \
2783 base, reg }, (val) }
2785 #define BOOL_ENTRY(name,val,base,reg) \
2786 struct sysparam_bool_entry entry_##name = { { get_bool_entry, set_bool_entry, init_bool_entry, \
2787 base, reg }, (val) }
2789 #define BOOL_ENTRY_MIRROR(name,val,base,reg,mirror_base) \
2790 struct sysparam_bool_entry entry_##name = { { get_bool_entry, set_bool_entry, init_bool_entry, \
2791 base, reg, mirror_base, reg }, (val) }
2793 #define TWIPS_ENTRY(name,val,base,reg) \
2794 struct sysparam_uint_entry entry_##name = { { get_twips_entry, set_twips_entry, init_int_entry, \
2795 base, reg }, (val) }
2797 #define YESNO_ENTRY(name,val,base,reg) \
2798 struct sysparam_bool_entry entry_##name = { { get_yesno_entry, set_yesno_entry, init_yesno_entry, \
2799 base, reg }, (val) }
2801 #define DWORD_ENTRY(name,val,base,reg) \
2802 struct sysparam_dword_entry entry_##name = { { get_dword_entry, set_dword_entry, init_dword_entry, \
2803 base, reg }, (val) }
2805 #define BINARY_ENTRY(name,data,base,reg) \
2806 struct sysparam_binary_entry entry_##name = { { get_binary_entry, set_binary_entry, init_binary_entry, \
2807 base, reg }, data, sizeof(data) }
2809 #define PATH_ENTRY(name,base,reg) \
2810 struct sysparam_path_entry entry_##name = { { get_path_entry, set_path_entry, init_path_entry, \
2811 base, reg } }
2813 #define FONT_ENTRY(name,weight,base,reg) \
2814 struct sysparam_font_entry entry_##name = { { get_font_entry, set_font_entry, init_font_entry, \
2815 base, reg }, (weight) }
2817 #define USERPREF_ENTRY(name,offset,mask) \
2818 struct sysparam_pref_entry entry_##name = { { get_userpref_entry, set_userpref_entry }, \
2819 &entry_USERPREFERENCESMASK, (offset), (mask) }
2821 static UINT_ENTRY( DRAGWIDTH, 4, DESKTOP_KEY, "DragWidth" );
2822 static UINT_ENTRY( DRAGHEIGHT, 4, DESKTOP_KEY, "DragHeight" );
2823 static UINT_ENTRY( DOUBLECLICKTIME, 500, MOUSE_KEY, "DoubleClickSpeed" );
2824 static UINT_ENTRY( FONTSMOOTHING, 2, DESKTOP_KEY, "FontSmoothing" );
2825 static UINT_ENTRY( GRIDGRANULARITY, 0, DESKTOP_KEY, "GridGranularity" );
2826 static UINT_ENTRY( KEYBOARDDELAY, 1, KEYBOARD_KEY, "KeyboardDelay" );
2827 static UINT_ENTRY( KEYBOARDSPEED, 31, KEYBOARD_KEY, "KeyboardSpeed" );
2828 static UINT_ENTRY( MENUSHOWDELAY, 400, DESKTOP_KEY, "MenuShowDelay" );
2829 static UINT_ENTRY( MINARRANGE, ARW_HIDE, METRICS_KEY, "MinArrange" );
2830 static UINT_ENTRY( MINHORZGAP, 0, METRICS_KEY, "MinHorzGap" );
2831 static UINT_ENTRY( MINVERTGAP, 0, METRICS_KEY, "MinVertGap" );
2832 static UINT_ENTRY( MINWIDTH, 154, METRICS_KEY, "MinWidth" );
2833 static UINT_ENTRY( MOUSEHOVERHEIGHT, 4, MOUSE_KEY, "MouseHoverHeight" );
2834 static UINT_ENTRY( MOUSEHOVERTIME, 400, MOUSE_KEY, "MouseHoverTime" );
2835 static UINT_ENTRY( MOUSEHOVERWIDTH, 4, MOUSE_KEY, "MouseHoverWidth" );
2836 static UINT_ENTRY( MOUSESPEED, 10, MOUSE_KEY, "MouseSensitivity" );
2837 static UINT_ENTRY( MOUSETRAILS, 0, MOUSE_KEY, "MouseTrails" );
2838 static UINT_ENTRY( SCREENSAVETIMEOUT, 300, DESKTOP_KEY, "ScreenSaveTimeOut" );
2839 static UINT_ENTRY( WHEELSCROLLCHARS, 3, DESKTOP_KEY, "WheelScrollChars" );
2840 static UINT_ENTRY( WHEELSCROLLLINES, 3, DESKTOP_KEY, "WheelScrollLines" );
2841 static UINT_ENTRY_MIRROR( DOUBLECLKHEIGHT, 4, MOUSE_KEY, "DoubleClickHeight", DESKTOP_KEY );
2842 static UINT_ENTRY_MIRROR( DOUBLECLKWIDTH, 4, MOUSE_KEY, "DoubleClickWidth", DESKTOP_KEY );
2843 static UINT_ENTRY_MIRROR( MENUDROPALIGNMENT, 0, DESKTOP_KEY, "MenuDropAlignment", VERSION_KEY );
2845 static INT_ENTRY( MOUSETHRESHOLD1, 6, MOUSE_KEY, "MouseThreshold1" );
2846 static INT_ENTRY( MOUSETHRESHOLD2, 10, MOUSE_KEY, "MouseThreshold2" );
2847 static INT_ENTRY( MOUSEACCELERATION, 1, MOUSE_KEY, "MouseSpeed" );
2849 static BOOL_ENTRY( BLOCKSENDINPUTRESETS, FALSE, DESKTOP_KEY, "BlockSendInputResets" );
2850 static BOOL_ENTRY( DRAGFULLWINDOWS, FALSE, DESKTOP_KEY, "DragFullWindows" );
2851 static BOOL_ENTRY( KEYBOARDPREF, TRUE, KEYBOARDPREF_KEY, "On" );
2852 static BOOL_ENTRY( LOWPOWERACTIVE, FALSE, DESKTOP_KEY, "LowPowerActive" );
2853 static BOOL_ENTRY( MOUSEBUTTONSWAP, FALSE, MOUSE_KEY, "SwapMouseButtons" );
2854 static BOOL_ENTRY( POWEROFFACTIVE, FALSE, DESKTOP_KEY, "PowerOffActive" );
2855 static BOOL_ENTRY( SCREENREADER, FALSE, SCREENREADER_KEY, "On" );
2856 static BOOL_ENTRY( SCREENSAVEACTIVE, TRUE, DESKTOP_KEY, "ScreenSaveActive" );
2857 static BOOL_ENTRY( SCREENSAVERRUNNING, FALSE, DESKTOP_KEY, "WINE_ScreenSaverRunning" ); /* FIXME - real value */
2858 static BOOL_ENTRY( SHOWSOUNDS, FALSE, SHOWSOUNDS_KEY, "On" );
2859 static BOOL_ENTRY( SNAPTODEFBUTTON, FALSE, MOUSE_KEY, "SnapToDefaultButton" );
2860 static BOOL_ENTRY_MIRROR( ICONTITLEWRAP, TRUE, DESKTOP_KEY, "IconTitleWrap", METRICS_KEY );
2861 static BOOL_ENTRY( AUDIODESC_ON, FALSE, AUDIODESC_KEY, "On" );
2863 static TWIPS_ENTRY( BORDER, -15, METRICS_KEY, "BorderWidth" );
2864 static TWIPS_ENTRY( CAPTIONHEIGHT, -270, METRICS_KEY, "CaptionHeight" );
2865 static TWIPS_ENTRY( CAPTIONWIDTH, -270, METRICS_KEY, "CaptionWidth" );
2866 static TWIPS_ENTRY( ICONHORIZONTALSPACING, -1125, METRICS_KEY, "IconSpacing" );
2867 static TWIPS_ENTRY( ICONVERTICALSPACING, -1125, METRICS_KEY, "IconVerticalSpacing" );
2868 static TWIPS_ENTRY( MENUHEIGHT, -270, METRICS_KEY, "MenuHeight" );
2869 static TWIPS_ENTRY( MENUWIDTH, -270, METRICS_KEY, "MenuWidth" );
2870 static TWIPS_ENTRY( PADDEDBORDERWIDTH, 0, METRICS_KEY, "PaddedBorderWidth" );
2871 static TWIPS_ENTRY( SCROLLHEIGHT, -240, METRICS_KEY, "ScrollHeight" );
2872 static TWIPS_ENTRY( SCROLLWIDTH, -240, METRICS_KEY, "ScrollWidth" );
2873 static TWIPS_ENTRY( SMCAPTIONHEIGHT, -225, METRICS_KEY, "SmCaptionHeight" );
2874 static TWIPS_ENTRY( SMCAPTIONWIDTH, -225, METRICS_KEY, "SmCaptionWidth" );
2876 static YESNO_ENTRY( BEEP, TRUE, SOUND_KEY, "Beep" );
2878 static DWORD_ENTRY( ACTIVEWINDOWTRACKING, 0, MOUSE_KEY, "ActiveWindowTracking" );
2879 static DWORD_ENTRY( ACTIVEWNDTRKTIMEOUT, 0, DESKTOP_KEY, "ActiveWndTrackTimeout" );
2880 static DWORD_ENTRY( CARETWIDTH, 1, DESKTOP_KEY, "CaretWidth" );
2881 static DWORD_ENTRY( DPISCALINGVER, 0, DESKTOP_KEY, "DpiScalingVer" );
2882 static DWORD_ENTRY( FOCUSBORDERHEIGHT, 1, DESKTOP_KEY, "FocusBorderHeight" );
2883 static DWORD_ENTRY( FOCUSBORDERWIDTH, 1, DESKTOP_KEY, "FocusBorderWidth" );
2884 static DWORD_ENTRY( FONTSMOOTHINGCONTRAST, 0, DESKTOP_KEY, "FontSmoothingGamma" );
2885 static DWORD_ENTRY( FONTSMOOTHINGORIENTATION, FE_FONTSMOOTHINGORIENTATIONRGB, DESKTOP_KEY, "FontSmoothingOrientation" );
2886 static DWORD_ENTRY( FONTSMOOTHINGTYPE, FE_FONTSMOOTHINGSTANDARD, DESKTOP_KEY, "FontSmoothingType" );
2887 static DWORD_ENTRY( FOREGROUNDFLASHCOUNT, 3, DESKTOP_KEY, "ForegroundFlashCount" );
2888 static DWORD_ENTRY( FOREGROUNDLOCKTIMEOUT, 0, DESKTOP_KEY, "ForegroundLockTimeout" );
2889 static DWORD_ENTRY( LOGPIXELS, 0, DESKTOP_KEY, "LogPixels" );
2890 static DWORD_ENTRY( MOUSECLICKLOCKTIME, 1200, DESKTOP_KEY, "ClickLockTime" );
2891 static DWORD_ENTRY( AUDIODESC_LOCALE, 0, AUDIODESC_KEY, "Locale" );
2893 static PATH_ENTRY( DESKPATTERN, DESKTOP_KEY, "Pattern" );
2894 static PATH_ENTRY( DESKWALLPAPER, DESKTOP_KEY, "Wallpaper" );
2896 static BYTE user_prefs[8] = { 0x30, 0x00, 0x00, 0x80, 0x12, 0x00, 0x00, 0x00 };
2897 static BINARY_ENTRY( USERPREFERENCESMASK, user_prefs, DESKTOP_KEY, "UserPreferencesMask" );
2899 static FONT_ENTRY( CAPTIONLOGFONT, FW_BOLD, METRICS_KEY, "CaptionFont" );
2900 static FONT_ENTRY( ICONTITLELOGFONT, FW_NORMAL, METRICS_KEY, "IconFont" );
2901 static FONT_ENTRY( MENULOGFONT, FW_NORMAL, METRICS_KEY, "MenuFont" );
2902 static FONT_ENTRY( MESSAGELOGFONT, FW_NORMAL, METRICS_KEY, "MessageFont" );
2903 static FONT_ENTRY( SMCAPTIONLOGFONT, FW_NORMAL, METRICS_KEY, "SmCaptionFont" );
2904 static FONT_ENTRY( STATUSLOGFONT, FW_NORMAL, METRICS_KEY, "StatusFont" );
2906 static USERPREF_ENTRY( MENUANIMATION, 0, 0x02 );
2907 static USERPREF_ENTRY( COMBOBOXANIMATION, 0, 0x04 );
2908 static USERPREF_ENTRY( LISTBOXSMOOTHSCROLLING, 0, 0x08 );
2909 static USERPREF_ENTRY( GRADIENTCAPTIONS, 0, 0x10 );
2910 static USERPREF_ENTRY( KEYBOARDCUES, 0, 0x20 );
2911 static USERPREF_ENTRY( ACTIVEWNDTRKZORDER, 0, 0x40 );
2912 static USERPREF_ENTRY( HOTTRACKING, 0, 0x80 );
2913 static USERPREF_ENTRY( MENUFADE, 1, 0x02 );
2914 static USERPREF_ENTRY( SELECTIONFADE, 1, 0x04 );
2915 static USERPREF_ENTRY( TOOLTIPANIMATION, 1, 0x08 );
2916 static USERPREF_ENTRY( TOOLTIPFADE, 1, 0x10 );
2917 static USERPREF_ENTRY( CURSORSHADOW, 1, 0x20 );
2918 static USERPREF_ENTRY( MOUSESONAR, 1, 0x40 );
2919 static USERPREF_ENTRY( MOUSECLICKLOCK, 1, 0x80 );
2920 static USERPREF_ENTRY( MOUSEVANISH, 2, 0x01 );
2921 static USERPREF_ENTRY( FLATMENU, 2, 0x02 );
2922 static USERPREF_ENTRY( DROPSHADOW, 2, 0x04 );
2923 static USERPREF_ENTRY( UIEFFECTS, 3, 0x80 );
2924 static USERPREF_ENTRY( DISABLEOVERLAPPEDCONTENT, 4, 0x01 );
2925 static USERPREF_ENTRY( CLIENTAREAANIMATION, 4, 0x02 );
2926 static USERPREF_ENTRY( CLEARTYPE, 4, 0x10 );
2927 static USERPREF_ENTRY( SPEECHRECOGNITION, 4, 0x20 );
2929 /* System parameter indexes */
2930 enum spi_index
2932 SPI_SETWORKAREA_IDX,
2933 SPI_INDEX_COUNT
2936 /* indicators whether system parameter value is loaded */
2937 static char spi_loaded[SPI_INDEX_COUNT];
2939 static struct sysparam_rgb_entry system_colors[] =
2941 #define RGB_ENTRY(name,val,reg) { { get_rgb_entry, set_rgb_entry, init_rgb_entry, COLORS_KEY, reg }, (val) }
2942 RGB_ENTRY( COLOR_SCROLLBAR, RGB(212, 208, 200), "Scrollbar" ),
2943 RGB_ENTRY( COLOR_BACKGROUND, RGB(58, 110, 165), "Background" ),
2944 RGB_ENTRY( COLOR_ACTIVECAPTION, RGB(10, 36, 106), "ActiveTitle" ),
2945 RGB_ENTRY( COLOR_INACTIVECAPTION, RGB(128, 128, 128), "InactiveTitle" ),
2946 RGB_ENTRY( COLOR_MENU, RGB(212, 208, 200), "Menu" ),
2947 RGB_ENTRY( COLOR_WINDOW, RGB(255, 255, 255), "Window" ),
2948 RGB_ENTRY( COLOR_WINDOWFRAME, RGB(0, 0, 0), "WindowFrame" ),
2949 RGB_ENTRY( COLOR_MENUTEXT, RGB(0, 0, 0), "MenuText" ),
2950 RGB_ENTRY( COLOR_WINDOWTEXT, RGB(0, 0, 0), "WindowText" ),
2951 RGB_ENTRY( COLOR_CAPTIONTEXT, RGB(255, 255, 255), "TitleText" ),
2952 RGB_ENTRY( COLOR_ACTIVEBORDER, RGB(212, 208, 200), "ActiveBorder" ),
2953 RGB_ENTRY( COLOR_INACTIVEBORDER, RGB(212, 208, 200), "InactiveBorder" ),
2954 RGB_ENTRY( COLOR_APPWORKSPACE, RGB(128, 128, 128), "AppWorkSpace" ),
2955 RGB_ENTRY( COLOR_HIGHLIGHT, RGB(10, 36, 106), "Hilight" ),
2956 RGB_ENTRY( COLOR_HIGHLIGHTTEXT, RGB(255, 255, 255), "HilightText" ),
2957 RGB_ENTRY( COLOR_BTNFACE, RGB(212, 208, 200), "ButtonFace" ),
2958 RGB_ENTRY( COLOR_BTNSHADOW, RGB(128, 128, 128), "ButtonShadow" ),
2959 RGB_ENTRY( COLOR_GRAYTEXT, RGB(128, 128, 128), "GrayText" ),
2960 RGB_ENTRY( COLOR_BTNTEXT, RGB(0, 0, 0), "ButtonText" ),
2961 RGB_ENTRY( COLOR_INACTIVECAPTIONTEXT, RGB(212, 208, 200), "InactiveTitleText" ),
2962 RGB_ENTRY( COLOR_BTNHIGHLIGHT, RGB(255, 255, 255), "ButtonHilight" ),
2963 RGB_ENTRY( COLOR_3DDKSHADOW, RGB(64, 64, 64), "ButtonDkShadow" ),
2964 RGB_ENTRY( COLOR_3DLIGHT, RGB(212, 208, 200), "ButtonLight" ),
2965 RGB_ENTRY( COLOR_INFOTEXT, RGB(0, 0, 0), "InfoText" ),
2966 RGB_ENTRY( COLOR_INFOBK, RGB(255, 255, 225), "InfoWindow" ),
2967 RGB_ENTRY( COLOR_ALTERNATEBTNFACE, RGB(181, 181, 181), "ButtonAlternateFace" ),
2968 RGB_ENTRY( COLOR_HOTLIGHT, RGB(0, 0, 200), "HotTrackingColor" ),
2969 RGB_ENTRY( COLOR_GRADIENTACTIVECAPTION, RGB(166, 202, 240), "GradientActiveTitle" ),
2970 RGB_ENTRY( COLOR_GRADIENTINACTIVECAPTION, RGB(192, 192, 192), "GradientInactiveTitle" ),
2971 RGB_ENTRY( COLOR_MENUHILIGHT, RGB(10, 36, 106), "MenuHilight" ),
2972 RGB_ENTRY( COLOR_MENUBAR, RGB(212, 208, 200), "MenuBar" )
2973 #undef RGB_ENTRY
2976 /* entries that are initialized by default in the registry */
2977 static union sysparam_all_entry * const default_entries[] =
2979 (union sysparam_all_entry *)&entry_ACTIVEWINDOWTRACKING,
2980 (union sysparam_all_entry *)&entry_ACTIVEWNDTRKTIMEOUT,
2981 (union sysparam_all_entry *)&entry_BEEP,
2982 (union sysparam_all_entry *)&entry_BLOCKSENDINPUTRESETS,
2983 (union sysparam_all_entry *)&entry_BORDER,
2984 (union sysparam_all_entry *)&entry_CAPTIONHEIGHT,
2985 (union sysparam_all_entry *)&entry_CAPTIONWIDTH,
2986 (union sysparam_all_entry *)&entry_CARETWIDTH,
2987 (union sysparam_all_entry *)&entry_DESKWALLPAPER,
2988 (union sysparam_all_entry *)&entry_DOUBLECLICKTIME,
2989 (union sysparam_all_entry *)&entry_DOUBLECLKHEIGHT,
2990 (union sysparam_all_entry *)&entry_DOUBLECLKWIDTH,
2991 (union sysparam_all_entry *)&entry_DRAGFULLWINDOWS,
2992 (union sysparam_all_entry *)&entry_DRAGHEIGHT,
2993 (union sysparam_all_entry *)&entry_DRAGWIDTH,
2994 (union sysparam_all_entry *)&entry_FOCUSBORDERHEIGHT,
2995 (union sysparam_all_entry *)&entry_FOCUSBORDERWIDTH,
2996 (union sysparam_all_entry *)&entry_FONTSMOOTHING,
2997 (union sysparam_all_entry *)&entry_FONTSMOOTHINGCONTRAST,
2998 (union sysparam_all_entry *)&entry_FONTSMOOTHINGORIENTATION,
2999 (union sysparam_all_entry *)&entry_FONTSMOOTHINGTYPE,
3000 (union sysparam_all_entry *)&entry_FOREGROUNDFLASHCOUNT,
3001 (union sysparam_all_entry *)&entry_FOREGROUNDLOCKTIMEOUT,
3002 (union sysparam_all_entry *)&entry_ICONHORIZONTALSPACING,
3003 (union sysparam_all_entry *)&entry_ICONTITLEWRAP,
3004 (union sysparam_all_entry *)&entry_ICONVERTICALSPACING,
3005 (union sysparam_all_entry *)&entry_KEYBOARDDELAY,
3006 (union sysparam_all_entry *)&entry_KEYBOARDPREF,
3007 (union sysparam_all_entry *)&entry_KEYBOARDSPEED,
3008 (union sysparam_all_entry *)&entry_LOWPOWERACTIVE,
3009 (union sysparam_all_entry *)&entry_MENUHEIGHT,
3010 (union sysparam_all_entry *)&entry_MENUSHOWDELAY,
3011 (union sysparam_all_entry *)&entry_MENUWIDTH,
3012 (union sysparam_all_entry *)&entry_MOUSEACCELERATION,
3013 (union sysparam_all_entry *)&entry_MOUSEBUTTONSWAP,
3014 (union sysparam_all_entry *)&entry_MOUSECLICKLOCKTIME,
3015 (union sysparam_all_entry *)&entry_MOUSEHOVERHEIGHT,
3016 (union sysparam_all_entry *)&entry_MOUSEHOVERTIME,
3017 (union sysparam_all_entry *)&entry_MOUSEHOVERWIDTH,
3018 (union sysparam_all_entry *)&entry_MOUSESPEED,
3019 (union sysparam_all_entry *)&entry_MOUSETHRESHOLD1,
3020 (union sysparam_all_entry *)&entry_MOUSETHRESHOLD2,
3021 (union sysparam_all_entry *)&entry_PADDEDBORDERWIDTH,
3022 (union sysparam_all_entry *)&entry_SCREENREADER,
3023 (union sysparam_all_entry *)&entry_SCROLLHEIGHT,
3024 (union sysparam_all_entry *)&entry_SCROLLWIDTH,
3025 (union sysparam_all_entry *)&entry_SHOWSOUNDS,
3026 (union sysparam_all_entry *)&entry_SMCAPTIONHEIGHT,
3027 (union sysparam_all_entry *)&entry_SMCAPTIONWIDTH,
3028 (union sysparam_all_entry *)&entry_SNAPTODEFBUTTON,
3029 (union sysparam_all_entry *)&entry_USERPREFERENCESMASK,
3030 (union sysparam_all_entry *)&entry_WHEELSCROLLCHARS,
3031 (union sysparam_all_entry *)&entry_WHEELSCROLLLINES,
3032 (union sysparam_all_entry *)&entry_AUDIODESC_LOCALE,
3033 (union sysparam_all_entry *)&entry_AUDIODESC_ON,
3036 void sysparams_init(void)
3039 DWORD i, dispos, dpi_scaling;
3040 WCHAR layout[KL_NAMELENGTH];
3041 pthread_mutexattr_t attr;
3042 HKEY hkey;
3044 static const WCHAR software_wineW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e'};
3045 static const WCHAR temporary_system_parametersW[] =
3046 {'T','e','m','p','o','r','a','r','y',' ','S','y','s','t','e','m',' ',
3047 'P','a','r','a','m','e','t','e','r','s'};
3048 static const WCHAR oneW[] = {'1',0};
3049 static const WCHAR kl_preloadW[] =
3050 {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d'};
3052 pthread_mutexattr_init( &attr );
3053 pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
3054 pthread_mutex_init( &user_mutex, &attr );
3055 pthread_mutexattr_destroy( &attr );
3057 if ((hkey = reg_create_key( hkcu_key, kl_preloadW, sizeof(kl_preloadW), 0, NULL )))
3059 if (NtUserGetKeyboardLayoutName( layout ))
3060 set_reg_value( hkey, oneW, REG_SZ, (const BYTE *)layout,
3061 (lstrlenW(layout) + 1) * sizeof(WCHAR) );
3062 NtClose( hkey );
3065 /* this one must be non-volatile */
3066 if (!(hkey = reg_create_key( hkcu_key, software_wineW, sizeof(software_wineW), 0, NULL )))
3068 ERR("Can't create wine registry branch\n");
3069 return;
3072 /* @@ Wine registry key: HKCU\Software\Wine\Temporary System Parameters */
3073 if (!(volatile_base_key = reg_create_key( hkey, temporary_system_parametersW,
3074 sizeof(temporary_system_parametersW),
3075 REG_OPTION_VOLATILE, &dispos )))
3076 ERR("Can't create non-permanent wine registry branch\n");
3078 NtClose( hkey );
3080 config_key = reg_create_key( NULL, config_keyW, sizeof(config_keyW), 0, NULL );
3082 get_dword_entry( (union sysparam_all_entry *)&entry_LOGPIXELS, 0, &system_dpi, 0 );
3083 if (!system_dpi) /* check fallback key */
3085 static const WCHAR log_pixelsW[] = {'L','o','g','P','i','x','e','l','s',0};
3086 static const WCHAR software_fontsW[] =
3087 {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s'};
3089 if ((hkey = reg_open_key( config_key, software_fontsW, sizeof(software_fontsW) )))
3091 char buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD)];
3092 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
3094 if (query_reg_value( hkey, log_pixelsW, value, sizeof(buffer) ) && value->Type == REG_DWORD)
3095 system_dpi = *(const DWORD *)value->Data;
3096 NtClose( hkey );
3099 if (!system_dpi) system_dpi = USER_DEFAULT_SCREEN_DPI;
3101 /* FIXME: what do the DpiScalingVer flags mean? */
3102 get_dword_entry( (union sysparam_all_entry *)&entry_DPISCALINGVER, 0, &dpi_scaling, 0 );
3103 if (!dpi_scaling) NtUserSetProcessDpiAwarenessContext( NTUSER_DPI_PER_MONITOR_AWARE, 0 );
3105 if (volatile_base_key && dispos == REG_CREATED_NEW_KEY) /* first process, initialize entries */
3107 for (i = 0; i < ARRAY_SIZE( default_entries ); i++)
3108 default_entries[i]->hdr.init( default_entries[i] );
3112 static BOOL update_desktop_wallpaper(void)
3114 /* FIXME: move implementation from user32 */
3115 entry_DESKWALLPAPER.hdr.loaded = entry_DESKPATTERN.hdr.loaded = FALSE;
3116 return TRUE;
3119 /***********************************************************************
3120 * NtUserSystemParametersInfoForDpi (win32u.@)
3122 BOOL WINAPI NtUserSystemParametersInfoForDpi( UINT action, UINT val, PVOID ptr, UINT winini, UINT dpi )
3124 BOOL ret = FALSE;
3126 switch (action)
3128 case SPI_GETICONTITLELOGFONT:
3129 ret = get_entry_dpi( &entry_ICONTITLELOGFONT, val, ptr, dpi );
3130 break;
3131 case SPI_GETNONCLIENTMETRICS:
3133 NONCLIENTMETRICSW *ncm = ptr;
3135 if (!ncm) break;
3136 ret = get_entry_dpi( &entry_BORDER, 0, &ncm->iBorderWidth, dpi ) &&
3137 get_entry_dpi( &entry_SCROLLWIDTH, 0, &ncm->iScrollWidth, dpi ) &&
3138 get_entry_dpi( &entry_SCROLLHEIGHT, 0, &ncm->iScrollHeight, dpi ) &&
3139 get_entry_dpi( &entry_CAPTIONWIDTH, 0, &ncm->iCaptionWidth, dpi ) &&
3140 get_entry_dpi( &entry_CAPTIONHEIGHT, 0, &ncm->iCaptionHeight, dpi ) &&
3141 get_entry_dpi( &entry_CAPTIONLOGFONT, 0, &ncm->lfCaptionFont, dpi ) &&
3142 get_entry_dpi( &entry_SMCAPTIONWIDTH, 0, &ncm->iSmCaptionWidth, dpi ) &&
3143 get_entry_dpi( &entry_SMCAPTIONHEIGHT, 0, &ncm->iSmCaptionHeight, dpi ) &&
3144 get_entry_dpi( &entry_SMCAPTIONLOGFONT, 0, &ncm->lfSmCaptionFont, dpi ) &&
3145 get_entry_dpi( &entry_MENUWIDTH, 0, &ncm->iMenuWidth, dpi ) &&
3146 get_entry_dpi( &entry_MENUHEIGHT, 0, &ncm->iMenuHeight, dpi ) &&
3147 get_entry_dpi( &entry_MENULOGFONT, 0, &ncm->lfMenuFont, dpi ) &&
3148 get_entry_dpi( &entry_STATUSLOGFONT, 0, &ncm->lfStatusFont, dpi ) &&
3149 get_entry_dpi( &entry_MESSAGELOGFONT, 0, &ncm->lfMessageFont, dpi );
3150 if (ret && ncm->cbSize == sizeof(NONCLIENTMETRICSW))
3151 ret = get_entry_dpi( &entry_PADDEDBORDERWIDTH, 0, &ncm->iPaddedBorderWidth, dpi );
3152 normalize_nonclientmetrics( ncm );
3153 break;
3155 case SPI_GETICONMETRICS:
3157 ICONMETRICSW *im = ptr;
3158 if (im && im->cbSize == sizeof(*im))
3159 ret = get_entry_dpi( &entry_ICONHORIZONTALSPACING, 0, &im->iHorzSpacing, dpi ) &&
3160 get_entry_dpi( &entry_ICONVERTICALSPACING, 0, &im->iVertSpacing, dpi ) &&
3161 get_entry_dpi( &entry_ICONTITLEWRAP, 0, &im->iTitleWrap, dpi ) &&
3162 get_entry_dpi( &entry_ICONTITLELOGFONT, 0, &im->lfFont, dpi );
3163 break;
3165 default:
3166 SetLastError( ERROR_INVALID_PARAMETER );
3167 break;
3169 return ret;
3172 /***********************************************************************
3173 * NtUserSystemParametersInfo (win32u.@)
3175 * Each system parameter has flag which shows whether the parameter
3176 * is loaded or not. Parameters, stored directly in SysParametersInfo are
3177 * loaded from registry only when they are requested and the flag is
3178 * "false", after the loading the flag is set to "true". On interprocess
3179 * notification of the parameter change the corresponding parameter flag is
3180 * set to "false". The parameter value will be reloaded when it is requested
3181 * the next time.
3182 * Parameters, backed by or depend on GetSystemMetrics are processed
3183 * differently. These parameters are always loaded. They are reloaded right
3184 * away on interprocess change notification. We can't do lazy loading because
3185 * we don't want to complicate GetSystemMetrics.
3186 * Parameters backed by driver settings are read from corresponding setting.
3187 * On the parameter change request the setting is changed. Interprocess change
3188 * notifications are ignored.
3189 * When parameter value is updated the changed value is stored in permanent
3190 * registry branch if saving is requested. Otherwise it is stored
3191 * in temporary branch
3193 * Some SPI values can also be stored as Twips values in the registry,
3194 * don't forget the conversion!
3196 BOOL WINAPI NtUserSystemParametersInfo( UINT action, UINT val, void *ptr, UINT winini )
3198 #define WINE_SPI_FIXME(x) \
3199 case x: \
3201 static BOOL warn = TRUE; \
3202 if (warn) \
3204 warn = FALSE; \
3205 FIXME( "Unimplemented action: %u (%s)\n", x, #x ); \
3208 SetLastError( ERROR_INVALID_SPI_VALUE ); \
3209 ret = FALSE; \
3210 break
3211 #define WINE_SPI_WARN(x) \
3212 case x: \
3213 WARN( "Ignored action: %u (%s)\n", x, #x ); \
3214 ret = TRUE; \
3215 break
3217 BOOL ret = user_driver->pSystemParametersInfo( action, val, ptr, winini );
3218 unsigned spi_idx = 0;
3220 if (!ret) switch (action)
3222 case SPI_GETBEEP:
3223 ret = get_entry( &entry_BEEP, val, ptr );
3224 break;
3225 case SPI_SETBEEP:
3226 ret = set_entry( &entry_BEEP, val, ptr, winini );
3227 break;
3228 case SPI_GETMOUSE:
3229 ret = get_entry( &entry_MOUSETHRESHOLD1, val, (INT *)ptr ) &&
3230 get_entry( &entry_MOUSETHRESHOLD2, val, (INT *)ptr + 1 ) &&
3231 get_entry( &entry_MOUSEACCELERATION, val, (INT *)ptr + 2 );
3232 break;
3233 case SPI_SETMOUSE:
3234 ret = set_entry( &entry_MOUSETHRESHOLD1, ((INT *)ptr)[0], ptr, winini ) &&
3235 set_entry( &entry_MOUSETHRESHOLD2, ((INT *)ptr)[1], ptr, winini ) &&
3236 set_entry( &entry_MOUSEACCELERATION, ((INT *)ptr)[2], ptr, winini );
3237 break;
3238 case SPI_GETBORDER:
3239 ret = get_entry( &entry_BORDER, val, ptr );
3240 if (*(INT*)ptr < 1) *(INT*)ptr = 1;
3241 break;
3242 case SPI_SETBORDER:
3243 ret = set_entry( &entry_BORDER, val, ptr, winini );
3244 break;
3245 case SPI_GETKEYBOARDSPEED:
3246 ret = get_entry( &entry_KEYBOARDSPEED, val, ptr );
3247 break;
3248 case SPI_SETKEYBOARDSPEED:
3249 if (val > 31) val = 31;
3250 ret = set_entry( &entry_KEYBOARDSPEED, val, ptr, winini );
3251 break;
3253 WINE_SPI_WARN(SPI_LANGDRIVER); /* not implemented in Windows */
3255 case SPI_ICONHORIZONTALSPACING:
3256 if (ptr != NULL)
3257 ret = get_entry( &entry_ICONHORIZONTALSPACING, val, ptr );
3258 else
3260 int min_val = map_to_dpi( 32, get_system_dpi() );
3261 ret = set_entry( &entry_ICONHORIZONTALSPACING, max( min_val, val ), ptr, winini );
3263 break;
3264 case SPI_GETSCREENSAVETIMEOUT:
3265 ret = get_entry( &entry_SCREENSAVETIMEOUT, val, ptr );
3266 break;
3267 case SPI_SETSCREENSAVETIMEOUT:
3268 ret = set_entry( &entry_SCREENSAVETIMEOUT, val, ptr, winini );
3269 break;
3270 case SPI_GETSCREENSAVEACTIVE:
3271 ret = get_entry( &entry_SCREENSAVEACTIVE, val, ptr );
3272 break;
3273 case SPI_SETSCREENSAVEACTIVE:
3274 ret = set_entry( &entry_SCREENSAVEACTIVE, val, ptr, winini );
3275 break;
3276 case SPI_GETGRIDGRANULARITY:
3277 ret = get_entry( &entry_GRIDGRANULARITY, val, ptr );
3278 break;
3279 case SPI_SETGRIDGRANULARITY:
3280 ret = set_entry( &entry_GRIDGRANULARITY, val, ptr, winini );
3281 break;
3282 case SPI_SETDESKWALLPAPER:
3283 if (!ptr || set_entry( &entry_DESKWALLPAPER, val, ptr, winini ))
3284 ret = update_desktop_wallpaper();
3285 break;
3286 case SPI_SETDESKPATTERN:
3287 if (!ptr || set_entry( &entry_DESKPATTERN, val, ptr, winini ))
3288 ret = update_desktop_wallpaper();
3289 break;
3290 case SPI_GETKEYBOARDDELAY:
3291 ret = get_entry( &entry_KEYBOARDDELAY, val, ptr );
3292 break;
3293 case SPI_SETKEYBOARDDELAY:
3294 ret = set_entry( &entry_KEYBOARDDELAY, val, ptr, winini );
3295 break;
3296 case SPI_ICONVERTICALSPACING:
3297 if (ptr != NULL)
3298 ret = get_entry( &entry_ICONVERTICALSPACING, val, ptr );
3299 else
3301 int min_val = map_to_dpi( 32, get_system_dpi() );
3302 ret = set_entry( &entry_ICONVERTICALSPACING, max( min_val, val ), ptr, winini );
3304 break;
3305 case SPI_GETICONTITLEWRAP:
3306 ret = get_entry( &entry_ICONTITLEWRAP, val, ptr );
3307 break;
3308 case SPI_SETICONTITLEWRAP:
3309 ret = set_entry( &entry_ICONTITLEWRAP, val, ptr, winini );
3310 break;
3311 case SPI_GETMENUDROPALIGNMENT:
3312 ret = get_entry( &entry_MENUDROPALIGNMENT, val, ptr );
3313 break;
3314 case SPI_SETMENUDROPALIGNMENT:
3315 ret = set_entry( &entry_MENUDROPALIGNMENT, val, ptr, winini );
3316 break;
3317 case SPI_SETDOUBLECLKWIDTH:
3318 ret = set_entry( &entry_DOUBLECLKWIDTH, val, ptr, winini );
3319 break;
3320 case SPI_SETDOUBLECLKHEIGHT:
3321 ret = set_entry( &entry_DOUBLECLKHEIGHT, val, ptr, winini );
3322 break;
3323 case SPI_GETICONTITLELOGFONT:
3324 ret = get_entry( &entry_ICONTITLELOGFONT, val, ptr );
3325 break;
3326 case SPI_SETDOUBLECLICKTIME:
3327 ret = set_entry( &entry_DOUBLECLICKTIME, val, ptr, winini );
3328 break;
3329 case SPI_SETMOUSEBUTTONSWAP:
3330 ret = set_entry( &entry_MOUSEBUTTONSWAP, val, ptr, winini );
3331 break;
3332 case SPI_SETICONTITLELOGFONT:
3333 ret = set_entry( &entry_ICONTITLELOGFONT, val, ptr, winini );
3334 break;
3335 case SPI_GETFASTTASKSWITCH:
3336 if (!ptr) return FALSE;
3337 *(BOOL *)ptr = TRUE;
3338 ret = TRUE;
3339 break;
3340 case SPI_SETFASTTASKSWITCH:
3341 /* the action is disabled */
3342 ret = FALSE;
3343 break;
3344 case SPI_SETDRAGFULLWINDOWS:
3345 ret = set_entry( &entry_DRAGFULLWINDOWS, val, ptr, winini );
3346 break;
3347 case SPI_GETDRAGFULLWINDOWS:
3348 ret = get_entry( &entry_DRAGFULLWINDOWS, val, ptr );
3349 break;
3350 case SPI_GETNONCLIENTMETRICS:
3352 NONCLIENTMETRICSW *nm = ptr;
3353 int padded_border;
3355 if (!ptr) return FALSE;
3357 ret = get_entry( &entry_BORDER, 0, &nm->iBorderWidth ) &&
3358 get_entry( &entry_PADDEDBORDERWIDTH, 0, &padded_border ) &&
3359 get_entry( &entry_SCROLLWIDTH, 0, &nm->iScrollWidth ) &&
3360 get_entry( &entry_SCROLLHEIGHT, 0, &nm->iScrollHeight ) &&
3361 get_entry( &entry_CAPTIONWIDTH, 0, &nm->iCaptionWidth ) &&
3362 get_entry( &entry_CAPTIONHEIGHT, 0, &nm->iCaptionHeight ) &&
3363 get_entry( &entry_CAPTIONLOGFONT, 0, &nm->lfCaptionFont ) &&
3364 get_entry( &entry_SMCAPTIONWIDTH, 0, &nm->iSmCaptionWidth ) &&
3365 get_entry( &entry_SMCAPTIONHEIGHT, 0, &nm->iSmCaptionHeight ) &&
3366 get_entry( &entry_SMCAPTIONLOGFONT, 0, &nm->lfSmCaptionFont ) &&
3367 get_entry( &entry_MENUWIDTH, 0, &nm->iMenuWidth ) &&
3368 get_entry( &entry_MENUHEIGHT, 0, &nm->iMenuHeight ) &&
3369 get_entry( &entry_MENULOGFONT, 0, &nm->lfMenuFont ) &&
3370 get_entry( &entry_STATUSLOGFONT, 0, &nm->lfStatusFont ) &&
3371 get_entry( &entry_MESSAGELOGFONT, 0, &nm->lfMessageFont );
3372 if (ret)
3374 nm->iBorderWidth += padded_border;
3375 if (nm->cbSize == sizeof(NONCLIENTMETRICSW)) nm->iPaddedBorderWidth = 0;
3377 normalize_nonclientmetrics( nm );
3378 break;
3380 case SPI_SETNONCLIENTMETRICS:
3382 LPNONCLIENTMETRICSW nm = ptr;
3383 int padded_border;
3385 if (nm && (nm->cbSize == sizeof(NONCLIENTMETRICSW) ||
3386 nm->cbSize == FIELD_OFFSET(NONCLIENTMETRICSW, iPaddedBorderWidth)))
3388 get_entry( &entry_PADDEDBORDERWIDTH, 0, &padded_border );
3390 ret = set_entry( &entry_BORDER, nm->iBorderWidth - padded_border, NULL, winini ) &&
3391 set_entry( &entry_SCROLLWIDTH, nm->iScrollWidth, NULL, winini ) &&
3392 set_entry( &entry_SCROLLHEIGHT, nm->iScrollHeight, NULL, winini ) &&
3393 set_entry( &entry_CAPTIONWIDTH, nm->iCaptionWidth, NULL, winini ) &&
3394 set_entry( &entry_CAPTIONHEIGHT, nm->iCaptionHeight, NULL, winini ) &&
3395 set_entry( &entry_SMCAPTIONWIDTH, nm->iSmCaptionWidth, NULL, winini ) &&
3396 set_entry( &entry_SMCAPTIONHEIGHT, nm->iSmCaptionHeight, NULL, winini ) &&
3397 set_entry( &entry_MENUWIDTH, nm->iMenuWidth, NULL, winini ) &&
3398 set_entry( &entry_MENUHEIGHT, nm->iMenuHeight, NULL, winini ) &&
3399 set_entry( &entry_MENULOGFONT, 0, &nm->lfMenuFont, winini ) &&
3400 set_entry( &entry_CAPTIONLOGFONT, 0, &nm->lfCaptionFont, winini ) &&
3401 set_entry( &entry_SMCAPTIONLOGFONT, 0, &nm->lfSmCaptionFont, winini ) &&
3402 set_entry( &entry_STATUSLOGFONT, 0, &nm->lfStatusFont, winini ) &&
3403 set_entry( &entry_MESSAGELOGFONT, 0, &nm->lfMessageFont, winini );
3405 break;
3407 case SPI_GETMINIMIZEDMETRICS:
3409 MINIMIZEDMETRICS *mm = ptr;
3410 if (mm && mm->cbSize == sizeof(*mm)) {
3411 ret = get_entry( &entry_MINWIDTH, 0, &mm->iWidth ) &&
3412 get_entry( &entry_MINHORZGAP, 0, &mm->iHorzGap ) &&
3413 get_entry( &entry_MINVERTGAP, 0, &mm->iVertGap ) &&
3414 get_entry( &entry_MINARRANGE, 0, &mm->iArrange );
3415 mm->iWidth = max( 0, mm->iWidth );
3416 mm->iHorzGap = max( 0, mm->iHorzGap );
3417 mm->iVertGap = max( 0, mm->iVertGap );
3418 mm->iArrange &= 0x0f;
3420 break;
3422 case SPI_SETMINIMIZEDMETRICS:
3424 MINIMIZEDMETRICS *mm = ptr;
3425 if (mm && mm->cbSize == sizeof(*mm))
3426 ret = set_entry( &entry_MINWIDTH, max( 0, mm->iWidth ), NULL, winini ) &&
3427 set_entry( &entry_MINHORZGAP, max( 0, mm->iHorzGap ), NULL, winini ) &&
3428 set_entry( &entry_MINVERTGAP, max( 0, mm->iVertGap ), NULL, winini ) &&
3429 set_entry( &entry_MINARRANGE, mm->iArrange & 0x0f, NULL, winini );
3430 break;
3432 case SPI_GETICONMETRICS:
3434 ICONMETRICSW *icon = ptr;
3435 if(icon && icon->cbSize == sizeof(*icon))
3437 ret = get_entry( &entry_ICONHORIZONTALSPACING, 0, &icon->iHorzSpacing ) &&
3438 get_entry( &entry_ICONVERTICALSPACING, 0, &icon->iVertSpacing ) &&
3439 get_entry( &entry_ICONTITLEWRAP, 0, &icon->iTitleWrap ) &&
3440 get_entry( &entry_ICONTITLELOGFONT, 0, &icon->lfFont );
3442 break;
3444 case SPI_SETICONMETRICS:
3446 ICONMETRICSW *icon = ptr;
3447 if (icon && icon->cbSize == sizeof(*icon))
3448 ret = set_entry( &entry_ICONVERTICALSPACING, max(32,icon->iVertSpacing), NULL, winini ) &&
3449 set_entry( &entry_ICONHORIZONTALSPACING, max(32,icon->iHorzSpacing), NULL, winini ) &&
3450 set_entry( &entry_ICONTITLEWRAP, icon->iTitleWrap, NULL, winini ) &&
3451 set_entry( &entry_ICONTITLELOGFONT, 0, &icon->lfFont, winini );
3452 break;
3454 case SPI_SETWORKAREA:
3456 if (!ptr) return FALSE;
3457 spi_idx = SPI_SETWORKAREA_IDX;
3458 work_area = *(RECT*)ptr;
3459 spi_loaded[spi_idx] = TRUE;
3460 ret = TRUE;
3461 break;
3463 case SPI_GETWORKAREA:
3465 if (!ptr) return FALSE;
3467 spi_idx = SPI_SETWORKAREA_IDX;
3468 if (!spi_loaded[spi_idx])
3470 struct monitor *monitor;
3472 if (!lock_display_devices()) return FALSE;
3474 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
3476 if (!(monitor->flags & MONITORINFOF_PRIMARY)) continue;
3477 work_area = monitor->rc_work;
3478 break;
3481 unlock_display_devices();
3482 spi_loaded[spi_idx] = TRUE;
3484 *(RECT *)ptr = map_dpi_rect( work_area, system_dpi, get_thread_dpi() );
3485 ret = TRUE;
3486 TRACE("work area %s\n", wine_dbgstr_rect( &work_area ));
3487 break;
3490 WINE_SPI_FIXME(SPI_SETPENWINDOWS);
3492 case SPI_GETFILTERKEYS:
3494 LPFILTERKEYS filter_keys = ptr;
3495 WARN("SPI_GETFILTERKEYS not fully implemented\n");
3496 if (filter_keys && filter_keys->cbSize == sizeof(FILTERKEYS))
3498 /* Indicate that no FilterKeys feature available */
3499 filter_keys->dwFlags = 0;
3500 filter_keys->iWaitMSec = 0;
3501 filter_keys->iDelayMSec = 0;
3502 filter_keys->iRepeatMSec = 0;
3503 filter_keys->iBounceMSec = 0;
3504 ret = TRUE;
3506 break;
3508 WINE_SPI_FIXME(SPI_SETFILTERKEYS);
3510 case SPI_GETTOGGLEKEYS:
3512 LPTOGGLEKEYS toggle_keys = ptr;
3513 WARN("SPI_GETTOGGLEKEYS not fully implemented\n");
3514 if (toggle_keys && toggle_keys->cbSize == sizeof(TOGGLEKEYS))
3516 /* Indicate that no ToggleKeys feature available */
3517 toggle_keys->dwFlags = 0;
3518 ret = TRUE;
3520 break;
3523 WINE_SPI_FIXME(SPI_SETTOGGLEKEYS);
3525 case SPI_GETMOUSEKEYS:
3527 MOUSEKEYS *mouse_keys = ptr;
3528 WARN("SPI_GETMOUSEKEYS not fully implemented\n");
3529 if (mouse_keys && mouse_keys->cbSize == sizeof(MOUSEKEYS))
3531 /* Indicate that no MouseKeys feature available */
3532 mouse_keys->dwFlags = 0;
3533 mouse_keys->iMaxSpeed = 360;
3534 mouse_keys->iTimeToMaxSpeed = 1000;
3535 mouse_keys->iCtrlSpeed = 0;
3536 mouse_keys->dwReserved1 = 0;
3537 mouse_keys->dwReserved2 = 0;
3538 ret = TRUE;
3540 break;
3543 WINE_SPI_FIXME(SPI_SETMOUSEKEYS);
3545 case SPI_GETSHOWSOUNDS:
3546 ret = get_entry( &entry_SHOWSOUNDS, val, ptr );
3547 break;
3548 case SPI_SETSHOWSOUNDS:
3549 ret = set_entry( &entry_SHOWSOUNDS, val, ptr, winini );
3550 break;
3551 case SPI_GETSTICKYKEYS:
3553 STICKYKEYS *sticky_keys = ptr;
3554 WARN("SPI_GETSTICKYKEYS not fully implemented\n");
3555 if (sticky_keys && sticky_keys->cbSize == sizeof(STICKYKEYS))
3557 /* Indicate that no StickyKeys feature available */
3558 sticky_keys->dwFlags = 0;
3559 ret = TRUE;
3561 break;
3564 WINE_SPI_FIXME(SPI_SETSTICKYKEYS);
3566 case SPI_GETACCESSTIMEOUT:
3568 ACCESSTIMEOUT *access_timeout = ptr;
3569 WARN("SPI_GETACCESSTIMEOUT not fully implemented\n");
3570 if (access_timeout && access_timeout->cbSize == sizeof(ACCESSTIMEOUT))
3572 /* Indicate that no accessibility features timeout is available */
3573 access_timeout->dwFlags = 0;
3574 access_timeout->iTimeOutMSec = 0;
3575 ret = TRUE;
3577 break;
3580 WINE_SPI_FIXME(SPI_SETACCESSTIMEOUT);
3582 case SPI_GETSERIALKEYS:
3584 LPSERIALKEYSW serial_keys = ptr;
3585 WARN("SPI_GETSERIALKEYS not fully implemented\n");
3586 if (serial_keys && serial_keys->cbSize == sizeof(SERIALKEYSW))
3588 /* Indicate that no SerialKeys feature available */
3589 serial_keys->dwFlags = 0;
3590 serial_keys->lpszActivePort = NULL;
3591 serial_keys->lpszPort = NULL;
3592 serial_keys->iBaudRate = 0;
3593 serial_keys->iPortState = 0;
3594 ret = TRUE;
3596 break;
3599 WINE_SPI_FIXME(SPI_SETSERIALKEYS);
3601 case SPI_GETSOUNDSENTRY:
3603 SOUNDSENTRYW *sound_sentry = ptr;
3604 WARN("SPI_GETSOUNDSENTRY not fully implemented\n");
3605 if (sound_sentry && sound_sentry->cbSize == sizeof(SOUNDSENTRYW))
3607 /* Indicate that no SoundSentry feature available */
3608 sound_sentry->dwFlags = 0;
3609 sound_sentry->iFSTextEffect = 0;
3610 sound_sentry->iFSTextEffectMSec = 0;
3611 sound_sentry->iFSTextEffectColorBits = 0;
3612 sound_sentry->iFSGrafEffect = 0;
3613 sound_sentry->iFSGrafEffectMSec = 0;
3614 sound_sentry->iFSGrafEffectColor = 0;
3615 sound_sentry->iWindowsEffect = 0;
3616 sound_sentry->iWindowsEffectMSec = 0;
3617 sound_sentry->lpszWindowsEffectDLL = 0;
3618 sound_sentry->iWindowsEffectOrdinal = 0;
3619 ret = TRUE;
3621 break;
3624 WINE_SPI_FIXME(SPI_SETSOUNDSENTRY);
3626 case SPI_GETHIGHCONTRAST:
3628 HIGHCONTRASTW *high_contrast = ptr;
3629 WARN("SPI_GETHIGHCONTRAST not fully implemented\n");
3630 if (high_contrast && high_contrast->cbSize == sizeof(HIGHCONTRASTW))
3632 /* Indicate that no high contrast feature available */
3633 high_contrast->dwFlags = 0;
3634 high_contrast->lpszDefaultScheme = NULL;
3635 ret = TRUE;
3637 break;
3640 WINE_SPI_FIXME(SPI_SETHIGHCONTRAST);
3642 case SPI_GETKEYBOARDPREF:
3643 ret = get_entry( &entry_KEYBOARDPREF, val, ptr );
3644 break;
3645 case SPI_SETKEYBOARDPREF:
3646 ret = set_entry( &entry_KEYBOARDPREF, val, ptr, winini );
3647 break;
3648 case SPI_GETSCREENREADER:
3649 ret = get_entry( &entry_SCREENREADER, val, ptr );
3650 break;
3651 case SPI_SETSCREENREADER:
3652 ret = set_entry( &entry_SCREENREADER, val, ptr, winini );
3653 break;
3655 case SPI_GETANIMATION:
3657 ANIMATIONINFO *anim_info = ptr;
3659 /* Tell it "disabled" */
3660 if (anim_info && anim_info->cbSize == sizeof(ANIMATIONINFO))
3662 /* Minimize and restore animation is disabled (nonzero == enabled) */
3663 anim_info->iMinAnimate = 0;
3664 ret = TRUE;
3666 break;
3669 WINE_SPI_WARN(SPI_SETANIMATION);
3671 case SPI_GETFONTSMOOTHING:
3672 ret = get_entry( &entry_FONTSMOOTHING, val, ptr );
3673 if (ret) *(UINT *)ptr = (*(UINT *)ptr != 0);
3674 break;
3675 case SPI_SETFONTSMOOTHING:
3676 val = val ? 2 : 0; /* Win NT4/2k/XP behavior */
3677 ret = set_entry( &entry_FONTSMOOTHING, val, ptr, winini );
3678 break;
3679 case SPI_SETDRAGWIDTH:
3680 ret = set_entry( &entry_DRAGWIDTH, val, ptr, winini );
3681 break;
3682 case SPI_SETDRAGHEIGHT:
3683 ret = set_entry( &entry_DRAGHEIGHT, val, ptr, winini );
3684 break;
3686 WINE_SPI_FIXME(SPI_SETHANDHELD);
3687 WINE_SPI_FIXME(SPI_GETLOWPOWERTIMEOUT);
3688 WINE_SPI_FIXME(SPI_GETPOWEROFFTIMEOUT);
3689 WINE_SPI_FIXME(SPI_SETLOWPOWERTIMEOUT);
3690 WINE_SPI_FIXME(SPI_SETPOWEROFFTIMEOUT);
3692 case SPI_GETLOWPOWERACTIVE:
3693 ret = get_entry( &entry_LOWPOWERACTIVE, val, ptr );
3694 break;
3695 case SPI_SETLOWPOWERACTIVE:
3696 ret = set_entry( &entry_LOWPOWERACTIVE, val, ptr, winini );
3697 break;
3698 case SPI_GETPOWEROFFACTIVE:
3699 ret = get_entry( &entry_POWEROFFACTIVE, val, ptr );
3700 break;
3701 case SPI_SETPOWEROFFACTIVE:
3702 ret = set_entry( &entry_POWEROFFACTIVE, val, ptr, winini );
3703 break;
3705 WINE_SPI_FIXME(SPI_SETCURSORS);
3706 WINE_SPI_FIXME(SPI_SETICONS);
3708 case SPI_GETDEFAULTINPUTLANG:
3709 ret = NtUserGetKeyboardLayout(0) != 0;
3710 break;
3712 WINE_SPI_FIXME(SPI_SETDEFAULTINPUTLANG);
3713 WINE_SPI_FIXME(SPI_SETLANGTOGGLE);
3715 case SPI_GETWINDOWSEXTENSION:
3716 WARN( "pretend no support for Win9x Plus! for now.\n" );
3717 ret = FALSE; /* yes, this is the result value */
3718 break;
3719 case SPI_SETMOUSETRAILS:
3720 ret = set_entry( &entry_MOUSETRAILS, val, ptr, winini );
3721 break;
3722 case SPI_GETMOUSETRAILS:
3723 ret = get_entry( &entry_MOUSETRAILS, val, ptr );
3724 break;
3725 case SPI_GETSNAPTODEFBUTTON:
3726 ret = get_entry( &entry_SNAPTODEFBUTTON, val, ptr );
3727 break;
3728 case SPI_SETSNAPTODEFBUTTON:
3729 ret = set_entry( &entry_SNAPTODEFBUTTON, val, ptr, winini );
3730 break;
3731 case SPI_SETSCREENSAVERRUNNING:
3732 ret = set_entry( &entry_SCREENSAVERRUNNING, val, ptr, winini );
3733 break;
3734 case SPI_GETMOUSEHOVERWIDTH:
3735 ret = get_entry( &entry_MOUSEHOVERWIDTH, val, ptr );
3736 break;
3737 case SPI_SETMOUSEHOVERWIDTH:
3738 ret = set_entry( &entry_MOUSEHOVERWIDTH, val, ptr, winini );
3739 break;
3740 case SPI_GETMOUSEHOVERHEIGHT:
3741 ret = get_entry( &entry_MOUSEHOVERHEIGHT, val, ptr );
3742 break;
3743 case SPI_SETMOUSEHOVERHEIGHT:
3744 ret = set_entry( &entry_MOUSEHOVERHEIGHT, val, ptr, winini );
3745 break;
3746 case SPI_GETMOUSEHOVERTIME:
3747 ret = get_entry( &entry_MOUSEHOVERTIME, val, ptr );
3748 break;
3749 case SPI_SETMOUSEHOVERTIME:
3750 ret = set_entry( &entry_MOUSEHOVERTIME, val, ptr, winini );
3751 break;
3752 case SPI_GETWHEELSCROLLLINES:
3753 ret = get_entry( &entry_WHEELSCROLLLINES, val, ptr );
3754 break;
3755 case SPI_SETWHEELSCROLLLINES:
3756 ret = set_entry( &entry_WHEELSCROLLLINES, val, ptr, winini );
3757 break;
3758 case SPI_GETMENUSHOWDELAY:
3759 ret = get_entry( &entry_MENUSHOWDELAY, val, ptr );
3760 break;
3761 case SPI_SETMENUSHOWDELAY:
3762 ret = set_entry( &entry_MENUSHOWDELAY, val, ptr, winini );
3763 break;
3764 case SPI_GETWHEELSCROLLCHARS:
3765 ret = get_entry( &entry_WHEELSCROLLCHARS, val, ptr );
3766 break;
3767 case SPI_SETWHEELSCROLLCHARS:
3768 ret = set_entry( &entry_WHEELSCROLLCHARS, val, ptr, winini );
3769 break;
3771 WINE_SPI_FIXME(SPI_GETSHOWIMEUI);
3772 WINE_SPI_FIXME(SPI_SETSHOWIMEUI);
3774 case SPI_GETMOUSESPEED:
3775 ret = get_entry( &entry_MOUSESPEED, val, ptr );
3776 break;
3777 case SPI_SETMOUSESPEED:
3778 ret = set_entry( &entry_MOUSESPEED, val, ptr, winini );
3779 break;
3780 case SPI_GETSCREENSAVERRUNNING:
3781 ret = get_entry( &entry_SCREENSAVERRUNNING, val, ptr );
3782 break;
3783 case SPI_GETDESKWALLPAPER:
3784 ret = get_entry( &entry_DESKWALLPAPER, val, ptr );
3785 break;
3786 case SPI_GETACTIVEWINDOWTRACKING:
3787 ret = get_entry( &entry_ACTIVEWINDOWTRACKING, val, ptr );
3788 break;
3789 case SPI_SETACTIVEWINDOWTRACKING:
3790 ret = set_entry( &entry_ACTIVEWINDOWTRACKING, val, ptr, winini );
3791 break;
3792 case SPI_GETMENUANIMATION:
3793 ret = get_entry( &entry_MENUANIMATION, val, ptr );
3794 break;
3795 case SPI_SETMENUANIMATION:
3796 ret = set_entry( &entry_MENUANIMATION, val, ptr, winini );
3797 break;
3798 case SPI_GETCOMBOBOXANIMATION:
3799 ret = get_entry( &entry_COMBOBOXANIMATION, val, ptr );
3800 break;
3801 case SPI_SETCOMBOBOXANIMATION:
3802 ret = set_entry( &entry_COMBOBOXANIMATION, val, ptr, winini );
3803 break;
3804 case SPI_GETLISTBOXSMOOTHSCROLLING:
3805 ret = get_entry( &entry_LISTBOXSMOOTHSCROLLING, val, ptr );
3806 break;
3807 case SPI_SETLISTBOXSMOOTHSCROLLING:
3808 ret = set_entry( &entry_LISTBOXSMOOTHSCROLLING, val, ptr, winini );
3809 break;
3810 case SPI_GETGRADIENTCAPTIONS:
3811 ret = get_entry( &entry_GRADIENTCAPTIONS, val, ptr );
3812 break;
3813 case SPI_SETGRADIENTCAPTIONS:
3814 ret = set_entry( &entry_GRADIENTCAPTIONS, val, ptr, winini );
3815 break;
3816 case SPI_GETKEYBOARDCUES:
3817 ret = get_entry( &entry_KEYBOARDCUES, val, ptr );
3818 break;
3819 case SPI_SETKEYBOARDCUES:
3820 ret = set_entry( &entry_KEYBOARDCUES, val, ptr, winini );
3821 break;
3822 case SPI_GETACTIVEWNDTRKZORDER:
3823 ret = get_entry( &entry_ACTIVEWNDTRKZORDER, val, ptr );
3824 break;
3825 case SPI_SETACTIVEWNDTRKZORDER:
3826 ret = set_entry( &entry_ACTIVEWNDTRKZORDER, val, ptr, winini );
3827 break;
3828 case SPI_GETHOTTRACKING:
3829 ret = get_entry( &entry_HOTTRACKING, val, ptr );
3830 break;
3831 case SPI_SETHOTTRACKING:
3832 ret = set_entry( &entry_HOTTRACKING, val, ptr, winini );
3833 break;
3834 case SPI_GETMENUFADE:
3835 ret = get_entry( &entry_MENUFADE, val, ptr );
3836 break;
3837 case SPI_SETMENUFADE:
3838 ret = set_entry( &entry_MENUFADE, val, ptr, winini );
3839 break;
3840 case SPI_GETSELECTIONFADE:
3841 ret = get_entry( &entry_SELECTIONFADE, val, ptr );
3842 break;
3843 case SPI_SETSELECTIONFADE:
3844 ret = set_entry( &entry_SELECTIONFADE, val, ptr, winini );
3845 break;
3846 case SPI_GETTOOLTIPANIMATION:
3847 ret = get_entry( &entry_TOOLTIPANIMATION, val, ptr );
3848 break;
3849 case SPI_SETTOOLTIPANIMATION:
3850 ret = set_entry( &entry_TOOLTIPANIMATION, val, ptr, winini );
3851 break;
3852 case SPI_GETTOOLTIPFADE:
3853 ret = get_entry( &entry_TOOLTIPFADE, val, ptr );
3854 break;
3855 case SPI_SETTOOLTIPFADE:
3856 ret = set_entry( &entry_TOOLTIPFADE, val, ptr, winini );
3857 break;
3858 case SPI_GETCURSORSHADOW:
3859 ret = get_entry( &entry_CURSORSHADOW, val, ptr );
3860 break;
3861 case SPI_SETCURSORSHADOW:
3862 ret = set_entry( &entry_CURSORSHADOW, val, ptr, winini );
3863 break;
3864 case SPI_GETMOUSESONAR:
3865 ret = get_entry( &entry_MOUSESONAR, val, ptr );
3866 break;
3867 case SPI_SETMOUSESONAR:
3868 ret = set_entry( &entry_MOUSESONAR, val, ptr, winini );
3869 break;
3870 case SPI_GETMOUSECLICKLOCK:
3871 ret = get_entry( &entry_MOUSECLICKLOCK, val, ptr );
3872 break;
3873 case SPI_SETMOUSECLICKLOCK:
3874 ret = set_entry( &entry_MOUSECLICKLOCK, val, ptr, winini );
3875 break;
3876 case SPI_GETMOUSEVANISH:
3877 ret = get_entry( &entry_MOUSEVANISH, val, ptr );
3878 break;
3879 case SPI_SETMOUSEVANISH:
3880 ret = set_entry( &entry_MOUSEVANISH, val, ptr, winini );
3881 break;
3882 case SPI_GETFLATMENU:
3883 ret = get_entry( &entry_FLATMENU, val, ptr );
3884 break;
3885 case SPI_SETFLATMENU:
3886 ret = set_entry( &entry_FLATMENU, val, ptr, winini );
3887 break;
3888 case SPI_GETDROPSHADOW:
3889 ret = get_entry( &entry_DROPSHADOW, val, ptr );
3890 break;
3891 case SPI_SETDROPSHADOW:
3892 ret = set_entry( &entry_DROPSHADOW, val, ptr, winini );
3893 break;
3894 case SPI_GETBLOCKSENDINPUTRESETS:
3895 ret = get_entry( &entry_BLOCKSENDINPUTRESETS, val, ptr );
3896 break;
3897 case SPI_SETBLOCKSENDINPUTRESETS:
3898 ret = set_entry( &entry_BLOCKSENDINPUTRESETS, val, ptr, winini );
3899 break;
3900 case SPI_GETUIEFFECTS:
3901 ret = get_entry( &entry_UIEFFECTS, val, ptr );
3902 break;
3903 case SPI_SETUIEFFECTS:
3904 /* FIXME: this probably should mask other UI effect values when unset */
3905 ret = set_entry( &entry_UIEFFECTS, val, ptr, winini );
3906 break;
3907 case SPI_GETDISABLEOVERLAPPEDCONTENT:
3908 ret = get_entry( &entry_DISABLEOVERLAPPEDCONTENT, val, ptr );
3909 break;
3910 case SPI_SETDISABLEOVERLAPPEDCONTENT:
3911 ret = set_entry( &entry_DISABLEOVERLAPPEDCONTENT, val, ptr, winini );
3912 break;
3913 case SPI_GETCLIENTAREAANIMATION:
3914 ret = get_entry( &entry_CLIENTAREAANIMATION, val, ptr );
3915 break;
3916 case SPI_SETCLIENTAREAANIMATION:
3917 ret = set_entry( &entry_CLIENTAREAANIMATION, val, ptr, winini );
3918 break;
3919 case SPI_GETCLEARTYPE:
3920 ret = get_entry( &entry_CLEARTYPE, val, ptr );
3921 break;
3922 case SPI_SETCLEARTYPE:
3923 ret = set_entry( &entry_CLEARTYPE, val, ptr, winini );
3924 break;
3925 case SPI_GETSPEECHRECOGNITION:
3926 ret = get_entry( &entry_SPEECHRECOGNITION, val, ptr );
3927 break;
3928 case SPI_SETSPEECHRECOGNITION:
3929 ret = set_entry( &entry_SPEECHRECOGNITION, val, ptr, winini );
3930 break;
3931 case SPI_GETFOREGROUNDLOCKTIMEOUT:
3932 ret = get_entry( &entry_FOREGROUNDLOCKTIMEOUT, val, ptr );
3933 break;
3934 case SPI_SETFOREGROUNDLOCKTIMEOUT:
3935 /* FIXME: this should check that the calling thread
3936 * is able to change the foreground window */
3937 ret = set_entry( &entry_FOREGROUNDLOCKTIMEOUT, val, ptr, winini );
3938 break;
3939 case SPI_GETACTIVEWNDTRKTIMEOUT:
3940 ret = get_entry( &entry_ACTIVEWNDTRKTIMEOUT, val, ptr );
3941 break;
3942 case SPI_SETACTIVEWNDTRKTIMEOUT:
3943 ret = get_entry( &entry_ACTIVEWNDTRKTIMEOUT, val, ptr );
3944 break;
3945 case SPI_GETFOREGROUNDFLASHCOUNT:
3946 ret = get_entry( &entry_FOREGROUNDFLASHCOUNT, val, ptr );
3947 break;
3948 case SPI_SETFOREGROUNDFLASHCOUNT:
3949 ret = set_entry( &entry_FOREGROUNDFLASHCOUNT, val, ptr, winini );
3950 break;
3951 case SPI_GETCARETWIDTH:
3952 ret = get_entry( &entry_CARETWIDTH, val, ptr );
3953 break;
3954 case SPI_SETCARETWIDTH:
3955 ret = set_entry( &entry_CARETWIDTH, val, ptr, winini );
3956 break;
3957 case SPI_GETMOUSECLICKLOCKTIME:
3958 ret = get_entry( &entry_MOUSECLICKLOCKTIME, val, ptr );
3959 break;
3960 case SPI_SETMOUSECLICKLOCKTIME:
3961 ret = set_entry( &entry_MOUSECLICKLOCKTIME, val, ptr, winini );
3962 break;
3963 case SPI_GETFONTSMOOTHINGTYPE:
3964 ret = get_entry( &entry_FONTSMOOTHINGTYPE, val, ptr );
3965 break;
3966 case SPI_SETFONTSMOOTHINGTYPE:
3967 ret = set_entry( &entry_FONTSMOOTHINGTYPE, val, ptr, winini );
3968 break;
3969 case SPI_GETFONTSMOOTHINGCONTRAST:
3970 ret = get_entry( &entry_FONTSMOOTHINGCONTRAST, val, ptr );
3971 break;
3972 case SPI_SETFONTSMOOTHINGCONTRAST:
3973 ret = set_entry( &entry_FONTSMOOTHINGCONTRAST, val, ptr, winini );
3974 break;
3975 case SPI_GETFOCUSBORDERWIDTH:
3976 ret = get_entry( &entry_FOCUSBORDERWIDTH, val, ptr );
3977 break;
3978 case SPI_GETFOCUSBORDERHEIGHT:
3979 ret = get_entry( &entry_FOCUSBORDERHEIGHT, val, ptr );
3980 break;
3981 case SPI_SETFOCUSBORDERWIDTH:
3982 ret = set_entry( &entry_FOCUSBORDERWIDTH, val, ptr, winini );
3983 break;
3984 case SPI_SETFOCUSBORDERHEIGHT:
3985 ret = set_entry( &entry_FOCUSBORDERHEIGHT, val, ptr, winini );
3986 break;
3987 case SPI_GETFONTSMOOTHINGORIENTATION:
3988 ret = get_entry( &entry_FONTSMOOTHINGORIENTATION, val, ptr );
3989 break;
3990 case SPI_SETFONTSMOOTHINGORIENTATION:
3991 ret = set_entry( &entry_FONTSMOOTHINGORIENTATION, val, ptr, winini );
3992 break;
3993 case SPI_GETAUDIODESCRIPTION:
3995 AUDIODESCRIPTION *audio = ptr;
3996 if (audio && audio->cbSize == sizeof(AUDIODESCRIPTION) && val == sizeof(AUDIODESCRIPTION) )
3998 ret = get_entry( &entry_AUDIODESC_ON, 0, &audio->Enabled ) &&
3999 get_entry( &entry_AUDIODESC_LOCALE, 0, &audio->Locale );
4001 break;
4003 case SPI_SETAUDIODESCRIPTION:
4005 AUDIODESCRIPTION *audio = ptr;
4006 if (audio && audio->cbSize == sizeof(AUDIODESCRIPTION) && val == sizeof(AUDIODESCRIPTION) )
4008 ret = set_entry( &entry_AUDIODESC_ON, 0, &audio->Enabled, winini) &&
4009 set_entry( &entry_AUDIODESC_LOCALE, 0, &audio->Locale, winini );
4011 break;
4013 default:
4014 FIXME( "Unknown action: %u\n", action );
4015 SetLastError( ERROR_INVALID_SPI_VALUE );
4016 ret = FALSE;
4017 break;
4020 if (ret && (winini & SPIF_UPDATEINIFILE))
4022 static const WCHAR emptyW[1];
4023 if (winini & (SPIF_SENDWININICHANGE | SPIF_SENDCHANGE))
4024 user_callbacks->pSendMessageTimeoutW( HWND_BROADCAST, WM_SETTINGCHANGE,
4025 action, (LPARAM) emptyW,
4026 SMTO_ABORTIFHUNG, 2000, NULL );
4028 TRACE( "(%u, %u, %p, %u) ret %d\n", action, val, ptr, winini, ret );
4029 return ret;
4031 #undef WINE_SPI_FIXME
4032 #undef WINE_SPI_WARN
4035 int get_system_metrics( int index )
4037 NONCLIENTMETRICSW ncm;
4038 MINIMIZEDMETRICS mm;
4039 ICONMETRICSW im;
4040 RECT rect;
4041 UINT ret;
4042 HDC hdc;
4044 /* some metrics are dynamic */
4045 switch (index)
4047 case SM_CXVSCROLL:
4048 case SM_CYHSCROLL:
4049 get_entry( &entry_SCROLLWIDTH, 0, &ret );
4050 return max( ret, 8 );
4051 case SM_CYCAPTION:
4052 ncm.cbSize = sizeof(ncm);
4053 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4054 return ncm.iCaptionHeight + 1;
4055 case SM_CXBORDER:
4056 case SM_CYBORDER:
4057 /* SM_C{X,Y}BORDER always returns 1 regardless of 'BorderWidth' value in registry */
4058 return 1;
4059 case SM_CXDLGFRAME:
4060 case SM_CYDLGFRAME:
4061 return 3;
4062 case SM_CYVTHUMB:
4063 case SM_CXHTHUMB:
4064 case SM_CYVSCROLL:
4065 case SM_CXHSCROLL:
4066 get_entry( &entry_SCROLLHEIGHT, 0, &ret );
4067 return max( ret, 8 );
4068 case SM_CXICON:
4069 case SM_CYICON:
4070 return map_to_dpi( 32, get_system_dpi() );
4071 case SM_CXCURSOR:
4072 case SM_CYCURSOR:
4073 ret = map_to_dpi( 32, get_system_dpi() );
4074 if (ret >= 64) return 64;
4075 if (ret >= 48) return 48;
4076 return 32;
4077 case SM_CYMENU:
4078 ncm.cbSize = sizeof(ncm);
4079 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4080 return ncm.iMenuHeight + 1;
4081 case SM_CXFULLSCREEN:
4082 /* see the remark for SM_CXMAXIMIZED, at least this formulation is correct */
4083 return get_system_metrics( SM_CXMAXIMIZED ) - 2 * get_system_metrics( SM_CXFRAME );
4084 case SM_CYFULLSCREEN:
4085 /* see the remark for SM_CYMAXIMIZED, at least this formulation is
4086 * correct */
4087 return get_system_metrics( SM_CYMAXIMIZED ) - get_system_metrics( SM_CYMIN );
4088 case SM_CYKANJIWINDOW:
4089 return 0;
4090 case SM_MOUSEPRESENT:
4091 return 1;
4092 case SM_DEBUG:
4093 return 0;
4094 case SM_SWAPBUTTON:
4095 get_entry( &entry_MOUSEBUTTONSWAP, 0, &ret );
4096 return ret;
4097 case SM_RESERVED1:
4098 case SM_RESERVED2:
4099 case SM_RESERVED3:
4100 case SM_RESERVED4:
4101 return 0;
4102 case SM_CXMIN:
4103 ncm.cbSize = sizeof(ncm);
4104 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4105 hdc = get_display_dc();
4106 get_text_metr_size( hdc, &ncm.lfCaptionFont, NULL, &ret );
4107 release_display_dc( hdc );
4108 return 3 * ncm.iCaptionWidth + ncm.iCaptionHeight + 4 * ret +
4109 2 * get_system_metrics( SM_CXFRAME ) + 4;
4110 case SM_CYMIN:
4111 return get_system_metrics( SM_CYCAPTION ) + 2 * get_system_metrics( SM_CYFRAME );
4112 case SM_CXSIZE:
4113 get_entry( &entry_CAPTIONWIDTH, 0, &ret );
4114 return max( ret, 8 );
4115 case SM_CYSIZE:
4116 ncm.cbSize = sizeof(ncm);
4117 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4118 return ncm.iCaptionHeight;
4119 case SM_CXFRAME:
4120 get_entry( &entry_BORDER, 0, &ret );
4121 ret = max( ret, 1 );
4122 return get_system_metrics( SM_CXDLGFRAME ) + ret;
4123 case SM_CYFRAME:
4124 get_entry( &entry_BORDER, 0, &ret );
4125 ret = max( ret, 1 );
4126 return get_system_metrics( SM_CYDLGFRAME ) + ret;
4127 case SM_CXMINTRACK:
4128 return get_system_metrics( SM_CXMIN );
4129 case SM_CYMINTRACK:
4130 return get_system_metrics( SM_CYMIN );
4131 case SM_CXDOUBLECLK:
4132 get_entry( &entry_DOUBLECLKWIDTH, 0, &ret );
4133 return ret;
4134 case SM_CYDOUBLECLK:
4135 get_entry( &entry_DOUBLECLKHEIGHT, 0, &ret );
4136 return ret;
4137 case SM_CXICONSPACING:
4138 im.cbSize = sizeof(im);
4139 NtUserSystemParametersInfo( SPI_GETICONMETRICS, sizeof(im), &im, 0 );
4140 return im.iHorzSpacing;
4141 case SM_CYICONSPACING:
4142 im.cbSize = sizeof(im);
4143 NtUserSystemParametersInfo( SPI_GETICONMETRICS, sizeof(im), &im, 0 );
4144 return im.iVertSpacing;
4145 case SM_MENUDROPALIGNMENT:
4146 NtUserSystemParametersInfo( SPI_GETMENUDROPALIGNMENT, 0, &ret, 0 );
4147 return ret;
4148 case SM_PENWINDOWS:
4149 return 0;
4150 case SM_DBCSENABLED:
4151 return get_cptable(get_acp())->MaximumCharacterSize > 1;
4152 case SM_CMOUSEBUTTONS:
4153 return 3;
4154 case SM_SECURE:
4155 return 0;
4156 case SM_CXEDGE:
4157 return get_system_metrics( SM_CXBORDER ) + 1;
4158 case SM_CYEDGE:
4159 return get_system_metrics( SM_CYBORDER ) + 1;
4160 case SM_CXMINSPACING:
4161 mm.cbSize = sizeof(mm);
4162 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
4163 return get_system_metrics( SM_CXMINIMIZED ) + mm.iHorzGap;
4164 case SM_CYMINSPACING:
4165 mm.cbSize = sizeof(mm);
4166 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
4167 return get_system_metrics( SM_CYMINIMIZED ) + mm.iVertGap;
4168 case SM_CXSMICON:
4169 case SM_CYSMICON:
4170 return map_to_dpi( 16, get_system_dpi() ) & ~1;
4171 case SM_CYSMCAPTION:
4172 ncm.cbSize = sizeof(ncm);
4173 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4174 return ncm.iSmCaptionHeight + 1;
4175 case SM_CXSMSIZE:
4176 get_entry( &entry_SMCAPTIONWIDTH, 0, &ret );
4177 return ret;
4178 case SM_CYSMSIZE:
4179 ncm.cbSize = sizeof(ncm);
4180 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4181 return ncm.iSmCaptionHeight;
4182 case SM_CXMENUSIZE:
4183 get_entry( &entry_MENUWIDTH, 0, &ret );
4184 return ret;
4185 case SM_CYMENUSIZE:
4186 ncm.cbSize = sizeof(ncm);
4187 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4188 return ncm.iMenuHeight;
4189 case SM_ARRANGE:
4190 mm.cbSize = sizeof(mm);
4191 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
4192 return mm.iArrange;
4193 case SM_CXMINIMIZED:
4194 mm.cbSize = sizeof(mm);
4195 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
4196 return mm.iWidth + 6;
4197 case SM_CYMINIMIZED:
4198 ncm.cbSize = sizeof(ncm);
4199 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4200 return ncm.iCaptionHeight + 6;
4201 case SM_CXMAXTRACK:
4202 return get_system_metrics( SM_CXVIRTUALSCREEN ) + 4 + 2 * get_system_metrics( SM_CXFRAME );
4203 case SM_CYMAXTRACK:
4204 return get_system_metrics( SM_CYVIRTUALSCREEN ) + 4 + 2 * get_system_metrics( SM_CYFRAME );
4205 case SM_CXMAXIMIZED:
4206 /* FIXME: subtract the width of any vertical application toolbars*/
4207 return get_system_metrics( SM_CXSCREEN ) + 2 * get_system_metrics( SM_CXFRAME );
4208 case SM_CYMAXIMIZED:
4209 /* FIXME: subtract the width of any horizontal application toolbars*/
4210 return get_system_metrics( SM_CYSCREEN ) + 2 * get_system_metrics( SM_CYCAPTION );
4211 case SM_NETWORK:
4212 return 3; /* FIXME */
4213 case SM_CLEANBOOT:
4214 return 0; /* 0 = ok, 1 = failsafe, 2 = failsafe + network */
4215 case SM_CXDRAG:
4216 get_entry( &entry_DRAGWIDTH, 0, &ret );
4217 return ret;
4218 case SM_CYDRAG:
4219 get_entry( &entry_DRAGHEIGHT, 0, &ret );
4220 return ret;
4221 case SM_SHOWSOUNDS:
4222 get_entry( &entry_SHOWSOUNDS, 0, &ret );
4223 return ret;
4224 case SM_CXMENUCHECK:
4225 case SM_CYMENUCHECK:
4227 TEXTMETRICW tm;
4228 ncm.cbSize = sizeof(ncm);
4229 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4230 hdc = get_display_dc();
4231 get_text_metr_size( hdc, &ncm.lfMenuFont, &tm, NULL );
4232 release_display_dc( hdc );
4233 return tm.tmHeight <= 0 ? 13 : ((tm.tmHeight + tm.tmExternalLeading + 1) / 2) * 2 - 1;
4235 case SM_SLOWMACHINE:
4236 return 0; /* Never true */
4237 case SM_MIDEASTENABLED:
4238 return 0; /* FIXME */
4239 case SM_MOUSEWHEELPRESENT:
4240 return 1;
4241 case SM_CXSCREEN:
4242 rect = get_primary_monitor_rect( get_thread_dpi() );
4243 return rect.right - rect.left;
4244 case SM_CYSCREEN:
4245 rect = get_primary_monitor_rect( get_thread_dpi() );
4246 return rect.bottom - rect.top;
4247 case SM_XVIRTUALSCREEN:
4248 rect = get_virtual_screen_rect( get_thread_dpi() );
4249 return rect.left;
4250 case SM_YVIRTUALSCREEN:
4251 rect = get_virtual_screen_rect( get_thread_dpi() );
4252 return rect.top;
4253 case SM_CXVIRTUALSCREEN:
4254 rect = get_virtual_screen_rect( get_thread_dpi() );
4255 return rect.right - rect.left;
4256 case SM_CYVIRTUALSCREEN:
4257 rect = get_virtual_screen_rect( get_thread_dpi() );
4258 return rect.bottom - rect.top;
4259 case SM_CMONITORS:
4260 if (!lock_display_devices()) return FALSE;
4261 ret = active_monitor_count();
4262 unlock_display_devices();
4263 return ret;
4264 case SM_SAMEDISPLAYFORMAT:
4265 return 1;
4266 case SM_IMMENABLED:
4267 return 0; /* FIXME */
4268 case SM_CXFOCUSBORDER:
4269 case SM_CYFOCUSBORDER:
4270 return 1;
4271 case SM_TABLETPC:
4272 case SM_MEDIACENTER:
4273 return 0;
4274 case SM_CMETRICS:
4275 return SM_CMETRICS;
4276 default:
4277 return 0;
4281 static int get_system_metrics_for_dpi( int index, unsigned int dpi )
4283 NONCLIENTMETRICSW ncm;
4284 ICONMETRICSW im;
4285 UINT ret;
4286 HDC hdc;
4288 /* some metrics are dynamic */
4289 switch (index)
4291 case SM_CXVSCROLL:
4292 case SM_CYHSCROLL:
4293 get_entry_dpi( &entry_SCROLLWIDTH, 0, &ret, dpi );
4294 return max( ret, 8 );
4295 case SM_CYCAPTION:
4296 ncm.cbSize = sizeof(ncm);
4297 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4298 return ncm.iCaptionHeight + 1;
4299 case SM_CYVTHUMB:
4300 case SM_CXHTHUMB:
4301 case SM_CYVSCROLL:
4302 case SM_CXHSCROLL:
4303 get_entry_dpi( &entry_SCROLLHEIGHT, 0, &ret, dpi );
4304 return max( ret, 8 );
4305 case SM_CXICON:
4306 case SM_CYICON:
4307 return map_to_dpi( 32, dpi );
4308 case SM_CXCURSOR:
4309 case SM_CYCURSOR:
4310 ret = map_to_dpi( 32, dpi );
4311 if (ret >= 64) return 64;
4312 if (ret >= 48) return 48;
4313 return 32;
4314 case SM_CYMENU:
4315 ncm.cbSize = sizeof(ncm);
4316 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4317 return ncm.iMenuHeight + 1;
4318 case SM_CXSIZE:
4319 get_entry_dpi( &entry_CAPTIONWIDTH, 0, &ret, dpi );
4320 return max( ret, 8 );
4321 case SM_CYSIZE:
4322 ncm.cbSize = sizeof(ncm);
4323 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4324 return ncm.iCaptionHeight;
4325 case SM_CXFRAME:
4326 get_entry_dpi( &entry_BORDER, 0, &ret, dpi );
4327 ret = max( ret, 1 );
4328 return get_system_metrics_for_dpi( SM_CXDLGFRAME, dpi ) + ret;
4329 case SM_CYFRAME:
4330 get_entry_dpi( &entry_BORDER, 0, &ret, dpi );
4331 ret = max( ret, 1 );
4332 return get_system_metrics_for_dpi( SM_CYDLGFRAME, dpi ) + ret;
4333 case SM_CXICONSPACING:
4334 im.cbSize = sizeof(im);
4335 NtUserSystemParametersInfoForDpi( SPI_GETICONMETRICS, sizeof(im), &im, 0, dpi );
4336 return im.iHorzSpacing;
4337 case SM_CYICONSPACING:
4338 im.cbSize = sizeof(im);
4339 NtUserSystemParametersInfoForDpi( SPI_GETICONMETRICS, sizeof(im), &im, 0, dpi );
4340 return im.iVertSpacing;
4341 case SM_CXSMICON:
4342 case SM_CYSMICON:
4343 return map_to_dpi( 16, dpi ) & ~1;
4344 case SM_CYSMCAPTION:
4345 ncm.cbSize = sizeof(ncm);
4346 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4347 return ncm.iSmCaptionHeight + 1;
4348 case SM_CXSMSIZE:
4349 get_entry_dpi( &entry_SMCAPTIONWIDTH, 0, &ret, dpi );
4350 return ret;
4351 case SM_CYSMSIZE:
4352 ncm.cbSize = sizeof(ncm);
4353 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4354 return ncm.iSmCaptionHeight;
4355 case SM_CXMENUSIZE:
4356 get_entry_dpi( &entry_MENUWIDTH, 0, &ret, dpi );
4357 return ret;
4358 case SM_CYMENUSIZE:
4359 ncm.cbSize = sizeof(ncm);
4360 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4361 return ncm.iMenuHeight;
4362 case SM_CXMENUCHECK:
4363 case SM_CYMENUCHECK:
4365 TEXTMETRICW tm;
4366 ncm.cbSize = sizeof(ncm);
4367 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
4368 hdc = get_display_dc();
4369 get_text_metr_size( hdc, &ncm.lfMenuFont, &tm, NULL);
4370 release_display_dc( hdc );
4371 return tm.tmHeight <= 0 ? 13 : ((tm.tmHeight + tm.tmExternalLeading - 1) | 1);
4373 default:
4374 return get_system_metrics( index );
4378 static COLORREF get_sys_color( int index )
4380 COLORREF ret = 0;
4382 if (index >= 0 && index < ARRAY_SIZE( system_colors ))
4383 get_entry( &system_colors[index], 0, &ret );
4384 return ret;
4387 static HBRUSH get_55aa_brush(void)
4389 static const WORD pattern[] = { 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa };
4390 static HBRUSH brush_55aa;
4392 if (!brush_55aa)
4394 HBITMAP bitmap = NtGdiCreateBitmap( 8, 8, 1, 1, pattern );
4395 HBRUSH brush = NtGdiCreatePatternBrushInternal( bitmap, FALSE, FALSE );
4396 NtGdiDeleteObjectApp( bitmap );
4397 make_gdi_object_system( brush, TRUE );
4398 if (InterlockedCompareExchangePointer( (void **)&brush_55aa, brush, 0 ))
4400 make_gdi_object_system( brush, FALSE );
4401 NtGdiDeleteObjectApp( brush );
4404 return brush_55aa;
4407 static HBRUSH get_sys_color_brush( unsigned int index )
4409 if (index == COLOR_55AA_BRUSH) return get_55aa_brush();
4410 if (index >= ARRAY_SIZE( system_colors )) return 0;
4412 if (!system_colors[index].brush)
4414 HBRUSH brush = NtGdiCreateSolidBrush( get_sys_color( index ), NULL );
4415 make_gdi_object_system( brush, TRUE );
4416 if (InterlockedCompareExchangePointer( (void **)&system_colors[index].brush, brush, 0 ))
4418 make_gdi_object_system( brush, FALSE );
4419 NtGdiDeleteObjectApp( brush );
4422 return system_colors[index].brush;
4425 static HPEN get_sys_color_pen( unsigned int index )
4427 if (index >= ARRAY_SIZE( system_colors )) return 0;
4429 if (!system_colors[index].pen)
4431 HPEN pen = NtGdiCreatePen( PS_SOLID, 1, get_sys_color( index ), NULL );
4432 make_gdi_object_system( pen, TRUE );
4433 if (InterlockedCompareExchangePointer( (void **)&system_colors[index].pen, pen, 0 ))
4435 make_gdi_object_system( pen, FALSE );
4436 NtGdiDeleteObjectApp( pen );
4439 return system_colors[index].pen;
4442 /**********************************************************************
4443 * NtUserGetDoubleClickTime (win32u.@)
4445 UINT WINAPI NtUserGetDoubleClickTime(void)
4447 UINT time = 0;
4449 get_entry( &entry_DOUBLECLICKTIME, 0, &time );
4450 if (!time) time = 500;
4451 return time;
4454 /*************************************************************************
4455 * NtUserSetSysColors (win32u.@)
4457 BOOL WINAPI NtUserSetSysColors( INT count, const INT *colors, const COLORREF *values )
4459 int i;
4461 if (IS_INTRESOURCE(colors)) return FALSE; /* stupid app passes a color instead of an array */
4463 for (i = 0; i < count; i++)
4464 if (colors[i] >= 0 && colors[i] <= ARRAY_SIZE( system_colors ))
4465 set_entry( &system_colors[colors[i]], values[i], 0, 0 );
4467 /* Send WM_SYSCOLORCHANGE message to all windows */
4468 user_callbacks->pSendMessageTimeoutW( HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0,
4469 SMTO_ABORTIFHUNG, 2000, NULL );
4470 /* Repaint affected portions of all visible windows */
4471 user_callbacks->pRedrawWindow( 0, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW |
4472 RDW_ALLCHILDREN );
4473 return TRUE;
4477 static DPI_AWARENESS dpi_awareness;
4479 /***********************************************************************
4480 * NtUserSetProcessDpiAwarenessContext (win32u.@)
4482 BOOL WINAPI NtUserSetProcessDpiAwarenessContext( ULONG awareness, ULONG unknown )
4484 switch (awareness)
4486 case NTUSER_DPI_UNAWARE:
4487 case NTUSER_DPI_SYSTEM_AWARE:
4488 case NTUSER_DPI_PER_MONITOR_AWARE:
4489 case NTUSER_DPI_PER_MONITOR_AWARE_V2:
4490 case NTUSER_DPI_PER_UNAWARE_GDISCALED:
4491 break;
4492 default:
4493 SetLastError( ERROR_INVALID_PARAMETER );
4494 return FALSE;
4497 return !InterlockedCompareExchange( &dpi_awareness, awareness, 0 );
4500 /***********************************************************************
4501 * NtUserGetProcessDpiAwarenessContext (win32u.@)
4503 ULONG WINAPI NtUserGetProcessDpiAwarenessContext( HANDLE process )
4505 if (process && process != GetCurrentProcess())
4507 WARN( "not supported on other process %p\n", process );
4508 return NTUSER_DPI_UNAWARE;
4511 if (!dpi_awareness) return NTUSER_DPI_UNAWARE;
4512 return dpi_awareness;
4515 static BOOL message_beep( UINT i )
4517 BOOL active = TRUE;
4518 NtUserSystemParametersInfo( SPI_GETBEEP, 0, &active, FALSE );
4519 if (active) user_driver->pBeep();
4520 return TRUE;
4523 static void thread_detach(void)
4525 struct user_thread_info *thread_info = get_user_thread_info();
4527 user_driver->pThreadDetach();
4529 free( thread_info->key_state );
4530 thread_info->key_state = 0;
4533 /***********************************************************************
4534 * NtUserCallOneParam (win32u.@)
4536 ULONG_PTR WINAPI NtUserCallNoParam( ULONG code )
4538 switch(code)
4540 case NtUserGetInputState:
4541 return get_input_state();
4542 /* temporary exports */
4543 case NtUserThreadDetach:
4544 thread_detach();
4545 return 0;
4546 default:
4547 FIXME( "invalid code %u\n", code );
4548 return 0;
4552 /***********************************************************************
4553 * NtUserCallOneParam (win32u.@)
4555 ULONG_PTR WINAPI NtUserCallOneParam( ULONG_PTR arg, ULONG code )
4557 switch(code)
4559 case NtUserCreateCursorIcon:
4560 return HandleToUlong( alloc_cursoricon_handle( arg ));
4561 case NtUserGetClipCursor:
4562 return get_clip_cursor( (RECT *)arg );
4563 case NtUserGetCursorPos:
4564 return get_cursor_pos( (POINT *)arg );
4565 case NtUserGetIconParam:
4566 return get_icon_param( UlongToHandle(arg) );
4567 case NtUserGetSysColor:
4568 return get_sys_color( arg );
4569 case NtUserRealizePalette:
4570 return realize_palette( UlongToHandle(arg) );
4571 case NtUserGetPrimaryMonitorRect:
4572 *(RECT *)arg = get_primary_monitor_rect( 0 );
4573 return 1;
4574 case NtUserGetSysColorBrush:
4575 return HandleToUlong( get_sys_color_brush(arg) );
4576 case NtUserGetSysColorPen:
4577 return HandleToUlong( get_sys_color_pen(arg) );
4578 case NtUserGetSystemMetrics:
4579 return get_system_metrics( arg );
4580 case NtUserGetVirtualScreenRect:
4581 *(RECT *)arg = get_virtual_screen_rect( 0 );
4582 return 1;
4583 case NtUserMessageBeep:
4584 return message_beep( arg );
4585 /* temporary exports */
4586 case NtUserCallHooks:
4588 const struct win_hook_params *params = (struct win_hook_params *)arg;
4589 return call_hooks( params->id, params->code, params->wparam, params->lparam,
4590 params->next_unicode );
4592 case NtUserFlushWindowSurfaces:
4593 flush_window_surfaces( arg );
4594 return 0;
4595 case NtUserGetDeskPattern:
4596 return get_entry( &entry_DESKPATTERN, 256, (WCHAR *)arg );
4597 case NtUserGetWinProcPtr:
4598 return (UINT_PTR)get_winproc_ptr( UlongToHandle(arg) );
4599 case NtUserHandleInternalMessage:
4601 MSG *msg = (MSG *)arg;
4602 return handle_internal_message( msg->hwnd, msg->message, msg->wParam, msg->lParam );
4604 case NtUserIncrementKeyStateCounter:
4605 return InterlockedAdd( &global_key_state_counter, arg );
4606 case NtUserLock:
4607 switch( arg )
4609 case 0: user_lock(); return 0;
4610 case 1: user_unlock(); return 0;
4611 default: user_check_not_lock(); return 0;
4613 case NtUserNextThreadWindow:
4614 return (UINT_PTR)next_thread_window_ptr( (HWND *)arg );
4615 case NtUserSetCallbacks:
4616 return (UINT_PTR)InterlockedExchangePointer( (void **)&user_callbacks, (void *)arg );
4617 default:
4618 FIXME( "invalid code %u\n", code );
4619 return 0;
4623 /***********************************************************************
4624 * NtUserCallTwoParam (win32u.@)
4626 ULONG_PTR WINAPI NtUserCallTwoParam( ULONG_PTR arg1, ULONG_PTR arg2, ULONG code )
4628 switch(code)
4630 case NtUserGetMonitorInfo:
4631 return get_monitor_info( UlongToHandle(arg1), (MONITORINFO *)arg2 );
4632 case NtUserGetSystemMetricsForDpi:
4633 return get_system_metrics_for_dpi( arg1, arg2 );
4634 case NtUserMirrorRgn:
4635 return mirror_window_region( UlongToHandle(arg1), UlongToHandle(arg2) );
4636 case NtUserMonitorFromRect:
4637 return HandleToUlong( monitor_from_rect( (const RECT *)arg1, arg2, get_thread_dpi() ));
4638 case NtUserSetIconParam:
4639 return set_icon_param( UlongToHandle(arg1), arg2 );
4640 case NtUserUnhookWindowsHook:
4641 return unhook_windows_hook( arg1, (HOOKPROC)arg2 );
4642 /* temporary exports */
4643 case NtUserAllocHandle:
4644 return HandleToUlong( alloc_user_handle( (struct user_object *)arg1, arg2 ));
4645 case NtUserAllocWinProc:
4646 return (UINT_PTR)alloc_winproc( (WNDPROC)arg1, arg2 );
4647 case NtUserFreeHandle:
4648 return (UINT_PTR)free_user_handle( UlongToHandle(arg1), arg2 );
4649 case NtUserGetHandlePtr:
4650 return (UINT_PTR)get_user_handle_ptr( UlongToHandle(arg1), arg2 );
4651 case NtUserRegisterWindowSurface:
4652 register_window_surface( (struct window_surface *)arg1, (struct window_surface *)arg2 );
4653 return 0;
4654 case NtUserSetHandlePtr:
4655 set_user_handle_ptr( UlongToHandle(arg1), (struct user_object *)arg2 );
4656 return 0;
4657 default:
4658 FIXME( "invalid code %u\n", code );
4659 return 0;