win32u: Move GetShellWindow implementation from user32.
[wine.git] / dlls / win32u / sysparams.c
blob89be3bbc6ed6340a8e8faad0a626e5d9fe0c1258
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};
172 static const WCHAR mode_countW[] = {'M','o','d','e','C','o','u','n','t',0};
174 static const char guid_devclass_displayA[] = "{4D36E968-E325-11CE-BFC1-08002BE10318}";
175 static const WCHAR guid_devclass_displayW[] =
176 {'{','4','D','3','6','E','9','6','8','-','E','3','2','5','-','1','1','C','E','-',
177 'B','F','C','1','-','0','8','0','0','2','B','E','1','0','3','1','8','}',0};
179 static const char guid_devclass_monitorA[] = "{4D36E96E-E325-11CE-BFC1-08002BE10318}";
180 static const WCHAR guid_devclass_monitorW[] =
181 {'{','4','D','3','6','E','9','6','E','-','E','3','2','5','-','1','1','C','E','-',
182 'B','F','C','1','-','0','8','0','0','2','B','E','1','0','3','1','8','}',0};
184 static const WCHAR guid_devinterface_display_adapterW[] =
185 {'{','5','B','4','5','2','0','1','D','-','F','2','F','2','-','4','F','3','B','-',
186 '8','5','B','B','-','3','0','F','F','1','F','9','5','3','5','9','9','}',0};
188 static const WCHAR guid_display_device_arrivalW[] =
189 {'{','1','C','A','0','5','1','8','0','-','A','6','9','9','-','4','5','0','A','-',
190 '9','A','0','C','-','D','E','4','F','B','E','3','D','D','D','8','9','}',0};
192 static const WCHAR guid_devinterface_monitorW[] =
193 {'{','E','6','F','0','7','B','5','F','-','E','E','9','7','-','4','A','9','0','-',
194 'B','0','7','6','-','3','3','F','5','7','B','F','4','E','A','A','7','}',0};
196 #define NEXT_DEVMODEW(mode) ((DEVMODEW *)((char *)((mode) + 1) + (mode)->dmDriverExtra))
198 /* Cached display device information */
199 struct display_device
201 WCHAR device_name[32]; /* DeviceName in DISPLAY_DEVICEW */
202 WCHAR device_string[128]; /* DeviceString in DISPLAY_DEVICEW */
203 DWORD state_flags; /* StateFlags in DISPLAY_DEVICEW */
204 WCHAR device_id[128]; /* DeviceID in DISPLAY_DEVICEW */
205 WCHAR interface_name[128]; /* DeviceID in DISPLAY_DEVICEW when EDD_GET_DEVICE_INTERFACE_NAME is set */
206 WCHAR device_key[128]; /* DeviceKey in DISPLAY_DEVICEW */
209 struct adapter
211 LONG refcount;
212 struct list entry;
213 struct display_device dev;
214 LUID gpu_luid;
215 unsigned int id;
216 const WCHAR *config_key;
217 unsigned int mode_count;
218 DEVMODEW *modes;
221 struct monitor
223 struct list entry;
224 struct display_device dev;
225 struct adapter *adapter;
226 HANDLE handle;
227 unsigned int id;
228 unsigned int flags;
229 unsigned int output_id;
230 RECT rc_monitor;
231 RECT rc_work;
232 BOOL is_clone;
235 static struct list adapters = LIST_INIT(adapters);
236 static struct list monitors = LIST_INIT(monitors);
237 static INT64 last_query_display_time;
238 static pthread_mutex_t display_lock = PTHREAD_MUTEX_INITIALIZER;
240 BOOL enable_thunk_lock = FALSE;
242 #define VIRTUAL_HMONITOR ((HMONITOR)(UINT_PTR)(0x10000 + 1))
243 static struct monitor virtual_monitor =
245 .handle = VIRTUAL_HMONITOR,
246 .flags = MONITORINFOF_PRIMARY,
247 .rc_monitor.right = 1024,
248 .rc_monitor.bottom = 768,
249 .rc_work.right = 1024,
250 .rc_work.bottom = 768,
251 .dev.state_flags = DISPLAY_DEVICE_ACTIVE | DISPLAY_DEVICE_ATTACHED,
254 /* the various registry keys that are used to store parameters */
255 enum parameter_key
257 COLORS_KEY,
258 DESKTOP_KEY,
259 KEYBOARD_KEY,
260 MOUSE_KEY,
261 METRICS_KEY,
262 SOUND_KEY,
263 VERSION_KEY,
264 SHOWSOUNDS_KEY,
265 KEYBOARDPREF_KEY,
266 SCREENREADER_KEY,
267 AUDIODESC_KEY,
268 NB_PARAM_KEYS
271 static const char *parameter_key_names[NB_PARAM_KEYS] =
273 "Control Panel\\Colors",
274 "Control Panel\\Desktop",
275 "Control Panel\\Keyboard",
276 "Control Panel\\Mouse",
277 "Control Panel\\Desktop\\WindowMetrics",
278 "Control Panel\\Sound",
279 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows",
280 "Control Panel\\Accessibility\\ShowSounds",
281 "Control Panel\\Accessibility\\Keyboard Preference",
282 "Control Panel\\Accessibility\\Blind Access",
283 "Control Panel\\Accessibility\\AudioDescription",
286 /* System parameters storage */
287 union sysparam_all_entry;
289 struct sysparam_entry
291 BOOL (*get)( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi );
292 BOOL (*set)( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags );
293 BOOL (*init)( union sysparam_all_entry *entry );
294 enum parameter_key base_key;
295 const char *regval;
296 enum parameter_key mirror_key;
297 const char *mirror;
298 BOOL loaded;
301 struct sysparam_uint_entry
303 struct sysparam_entry hdr;
304 UINT val;
307 struct sysparam_bool_entry
309 struct sysparam_entry hdr;
310 BOOL val;
313 struct sysparam_dword_entry
315 struct sysparam_entry hdr;
316 DWORD val;
319 struct sysparam_rgb_entry
321 struct sysparam_entry hdr;
322 COLORREF val;
323 HBRUSH brush;
324 HPEN pen;
327 struct sysparam_binary_entry
329 struct sysparam_entry hdr;
330 void *ptr;
331 size_t size;
334 struct sysparam_path_entry
336 struct sysparam_entry hdr;
337 WCHAR *path;
340 struct sysparam_font_entry
342 struct sysparam_entry hdr;
343 UINT weight;
344 LOGFONTW val;
345 WCHAR fullname[LF_FACESIZE];
348 struct sysparam_pref_entry
350 struct sysparam_entry hdr;
351 union sysparam_all_entry *parent;
352 UINT offset;
353 UINT mask;
356 union sysparam_all_entry
358 struct sysparam_entry hdr;
359 struct sysparam_uint_entry uint;
360 struct sysparam_bool_entry bool;
361 struct sysparam_dword_entry dword;
362 struct sysparam_rgb_entry rgb;
363 struct sysparam_binary_entry bin;
364 struct sysparam_path_entry path;
365 struct sysparam_font_entry font;
366 struct sysparam_pref_entry pref;
369 static UINT system_dpi;
370 static RECT work_area;
371 static DWORD process_layout = ~0u;
373 static HDC display_dc;
374 static pthread_mutex_t display_dc_lock = PTHREAD_MUTEX_INITIALIZER;
376 static pthread_mutex_t user_mutex;
377 static unsigned int user_lock_thread, user_lock_rec;
379 void user_lock(void)
381 pthread_mutex_lock( &user_mutex );
382 if (!user_lock_rec++) user_lock_thread = GetCurrentThreadId();
385 void user_unlock(void)
387 if (!--user_lock_rec) user_lock_thread = 0;
388 pthread_mutex_unlock( &user_mutex );
391 void user_check_not_lock(void)
393 if (user_lock_thread == GetCurrentThreadId())
395 ERR( "BUG: holding USER lock\n" );
396 assert( 0 );
400 static HANDLE get_display_device_init_mutex( void )
402 WCHAR bufferW[256];
403 UNICODE_STRING name = {.Buffer = bufferW};
404 OBJECT_ATTRIBUTES attr;
405 char buffer[256];
406 HANDLE mutex;
408 snprintf( buffer, ARRAY_SIZE(buffer), "\\Sessions\\%u\\BaseNamedObjects\\display_device_init",
409 (int)NtCurrentTeb()->Peb->SessionId );
410 name.Length = name.MaximumLength = asciiz_to_unicode( bufferW, buffer );
412 InitializeObjectAttributes( &attr, &name, OBJ_OPENIF, NULL, NULL );
413 if (NtCreateMutant( &mutex, MUTEX_ALL_ACCESS, &attr, FALSE ) < 0) return 0;
414 NtWaitForSingleObject( mutex, FALSE, NULL );
415 return mutex;
418 static void release_display_device_init_mutex( HANDLE mutex )
420 NtReleaseMutant( mutex, NULL );
421 NtClose( mutex );
424 static struct adapter *adapter_acquire( struct adapter *adapter )
426 InterlockedIncrement( &adapter->refcount );
427 return adapter;
430 static void adapter_release( struct adapter *adapter )
432 if (!InterlockedDecrement( &adapter->refcount ))
434 free( adapter->modes );
435 free( adapter );
439 C_ASSERT(sizeof(DEVMODEW) - offsetof(DEVMODEW, dmFields) == 0x94);
441 static BOOL write_adapter_mode( HKEY adapter_key, UINT index, const DEVMODEW *mode )
443 WCHAR bufferW[MAX_PATH] = {0};
444 char buffer[MAX_PATH];
446 sprintf( buffer, "Modes\\%08X", index );
447 asciiz_to_unicode( bufferW, buffer );
448 return set_reg_value( adapter_key, bufferW, REG_BINARY, &mode->dmFields, sizeof(*mode) - offsetof(DEVMODEW, dmFields) );
451 static BOOL read_adapter_mode( HKEY adapter_key, UINT index, DEVMODEW *mode )
453 char value_buf[offsetof(KEY_VALUE_PARTIAL_INFORMATION, Data[sizeof(*mode)])];
454 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)value_buf;
455 WCHAR bufferW[MAX_PATH] = {0};
456 char buffer[MAX_PATH];
458 sprintf( buffer, "Modes\\%08X", index );
459 asciiz_to_unicode( bufferW, buffer );
460 if (!query_reg_value( adapter_key, bufferW, value, sizeof(value_buf) )) return FALSE;
462 memcpy( &mode->dmFields, value->Data, sizeof(*mode) - offsetof(DEVMODEW, dmFields) );
463 return TRUE;
466 static BOOL adapter_get_registry_settings( const struct adapter *adapter, DEVMODEW *mode )
468 BOOL ret = FALSE;
469 HANDLE mutex;
470 HKEY hkey;
472 mutex = get_display_device_init_mutex();
474 if (!config_key && !(config_key = reg_open_key( NULL, config_keyW, sizeof(config_keyW) ))) ret = FALSE;
475 else if (!(hkey = reg_open_key( config_key, adapter->config_key, lstrlenW( adapter->config_key ) * sizeof(WCHAR) ))) ret = FALSE;
476 else
478 ret = read_adapter_mode( hkey, ENUM_REGISTRY_SETTINGS, mode );
479 NtClose( hkey );
482 release_display_device_init_mutex( mutex );
483 return ret;
486 static BOOL adapter_set_registry_settings( const struct adapter *adapter, const DEVMODEW *mode )
488 HANDLE mutex;
489 HKEY hkey;
490 BOOL ret;
492 mutex = get_display_device_init_mutex();
494 if (!config_key && !(config_key = reg_open_key( NULL, config_keyW, sizeof(config_keyW) ))) ret = FALSE;
495 if (!(hkey = reg_open_key( config_key, adapter->config_key, lstrlenW( adapter->config_key ) * sizeof(WCHAR) ))) ret = FALSE;
496 else
498 ret = write_adapter_mode( hkey, ENUM_REGISTRY_SETTINGS, mode );
499 NtClose( hkey );
502 release_display_device_init_mutex( mutex );
503 return ret;
506 static BOOL adapter_get_current_settings( const struct adapter *adapter, DEVMODEW *mode )
508 BOOL is_primary = !!(adapter->dev.state_flags & DISPLAY_DEVICE_PRIMARY_DEVICE);
509 HANDLE mutex;
510 HKEY hkey;
511 BOOL ret;
513 if ((ret = user_driver->pGetCurrentDisplaySettings( adapter->dev.device_name, is_primary, mode ))) return TRUE;
515 /* default implementation: read current display settings from the registry. */
517 mutex = get_display_device_init_mutex();
519 if (!config_key && !(config_key = reg_open_key( NULL, config_keyW, sizeof(config_keyW) ))) ret = FALSE;
520 else if (!(hkey = reg_open_key( config_key, adapter->config_key, lstrlenW( adapter->config_key ) * sizeof(WCHAR) ))) ret = FALSE;
521 else
523 ret = read_adapter_mode( hkey, ENUM_CURRENT_SETTINGS, mode );
524 NtClose( hkey );
527 release_display_device_init_mutex( mutex );
528 return ret;
531 static BOOL adapter_set_current_settings( const struct adapter *adapter, const DEVMODEW *mode )
533 HANDLE mutex;
534 HKEY hkey;
535 BOOL ret;
537 mutex = get_display_device_init_mutex();
539 if (!config_key && !(config_key = reg_open_key( NULL, config_keyW, sizeof(config_keyW) ))) ret = FALSE;
540 if (!(hkey = reg_open_key( config_key, adapter->config_key, lstrlenW( adapter->config_key ) * sizeof(WCHAR) ))) ret = FALSE;
541 else
543 ret = write_adapter_mode( hkey, ENUM_CURRENT_SETTINGS, mode );
544 NtClose( hkey );
547 release_display_device_init_mutex( mutex );
548 return ret;
551 static int mode_compare(const void *p1, const void *p2)
553 BOOL a_interlaced, b_interlaced, a_stretched, b_stretched;
554 DWORD a_width, a_height, b_width, b_height;
555 const DEVMODEW *a = p1, *b = p2;
556 int ret;
558 /* Depth in descending order */
559 if ((ret = b->dmBitsPerPel - a->dmBitsPerPel)) return ret;
561 /* Use the width and height in landscape mode for comparison */
562 if (a->dmDisplayOrientation == DMDO_DEFAULT || a->dmDisplayOrientation == DMDO_180)
564 a_width = a->dmPelsWidth;
565 a_height = a->dmPelsHeight;
567 else
569 a_width = a->dmPelsHeight;
570 a_height = a->dmPelsWidth;
573 if (b->dmDisplayOrientation == DMDO_DEFAULT || b->dmDisplayOrientation == DMDO_180)
575 b_width = b->dmPelsWidth;
576 b_height = b->dmPelsHeight;
578 else
580 b_width = b->dmPelsHeight;
581 b_height = b->dmPelsWidth;
584 /* Width in ascending order */
585 if ((ret = a_width - b_width)) return ret;
587 /* Height in ascending order */
588 if ((ret = a_height - b_height)) return ret;
590 /* Frequency in descending order */
591 if ((ret = b->dmDisplayFrequency - a->dmDisplayFrequency)) return ret;
593 /* Orientation in ascending order */
594 if ((ret = a->dmDisplayOrientation - b->dmDisplayOrientation)) return ret;
596 if (!(a->dmFields & DM_DISPLAYFLAGS)) a_interlaced = FALSE;
597 else a_interlaced = !!(a->dmDisplayFlags & DM_INTERLACED);
598 if (!(b->dmFields & DM_DISPLAYFLAGS)) b_interlaced = FALSE;
599 else b_interlaced = !!(b->dmDisplayFlags & DM_INTERLACED);
601 /* Interlaced in ascending order */
602 if ((ret = a_interlaced - b_interlaced)) return ret;
604 if (!(a->dmFields & DM_DISPLAYFIXEDOUTPUT)) a_stretched = FALSE;
605 else a_stretched = a->dmDisplayFixedOutput == DMDFO_STRETCH;
606 if (!(b->dmFields & DM_DISPLAYFIXEDOUTPUT)) b_stretched = FALSE;
607 else b_stretched = b->dmDisplayFixedOutput == DMDFO_STRETCH;
609 /* Stretched in ascending order */
610 if ((ret = a_stretched - b_stretched)) return ret;
612 return 0;
615 static unsigned int query_reg_subkey_value( HKEY hkey, const WCHAR *name, unsigned int name_size,
616 KEY_VALUE_PARTIAL_INFORMATION *value, unsigned int size )
618 HKEY subkey;
620 if (!(subkey = reg_open_key( hkey, name, name_size ))) return 0;
621 size = query_reg_value( subkey, NULL, value, size );
622 NtClose( subkey );
623 return size;
626 static BOOL read_display_adapter_settings( unsigned int index, struct adapter *info )
628 char buffer[4096];
629 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
630 WCHAR *value_str = (WCHAR *)value->Data;
631 DEVMODEW *mode;
632 DWORD i, size;
633 HKEY hkey;
635 if (!enum_key && !(enum_key = reg_open_key( NULL, enum_keyW, sizeof(enum_keyW) )))
636 return FALSE;
638 /* Find adapter */
639 sprintf( buffer, "\\Device\\Video%d", index );
640 size = query_reg_ascii_value( video_key, buffer, value, sizeof(buffer) );
641 if (!size || value->Type != REG_SZ ||
642 value->DataLength <= sizeof("\\Registry\\Machine\\") * sizeof(WCHAR))
643 return FALSE;
645 /* DeviceKey */
646 memcpy( info->dev.device_key, value_str, value->DataLength );
647 info->config_key = info->dev.device_key + sizeof("\\Registry\\Machine\\") - 1;
649 if (!(hkey = reg_open_key( NULL, value_str, value->DataLength - sizeof(WCHAR) )))
650 return FALSE;
652 /* DeviceString */
653 if (query_reg_value( hkey, driver_descW, value, sizeof(buffer) ) && value->Type == REG_SZ)
654 memcpy( info->dev.device_string, value_str, value->DataLength );
655 NtClose( hkey );
657 /* DeviceName */
658 sprintf( buffer, "\\\\.\\DISPLAY%d", index + 1 );
659 asciiz_to_unicode( info->dev.device_name, buffer );
661 if (!(hkey = reg_open_key( config_key, info->config_key,
662 lstrlenW( info->config_key ) * sizeof(WCHAR) )))
663 return FALSE;
665 /* StateFlags */
666 if (query_reg_value( hkey, state_flagsW, value, sizeof(buffer) ) && value->Type == REG_DWORD)
667 info->dev.state_flags = *(const DWORD *)value->Data;
669 /* Interface name */
670 info->dev.interface_name[0] = 0;
672 /* ModeCount */
673 if (query_reg_value( hkey, mode_countW, value, sizeof(buffer) ) && value->Type == REG_DWORD)
674 info->mode_count = *(const DWORD *)value->Data;
676 /* Modes, allocate an extra mode for easier iteration */
677 if ((info->modes = calloc( info->mode_count + 1, sizeof(DEVMODEW) )))
679 for (i = 0, mode = info->modes; i < info->mode_count; i++)
681 mode->dmSize = offsetof(DEVMODEW, dmICMMethod);
682 if (!read_adapter_mode( hkey, i, mode )) break;
683 mode = NEXT_DEVMODEW(mode);
685 info->mode_count = i;
687 qsort(info->modes, info->mode_count, sizeof(*info->modes) + info->modes->dmDriverExtra, mode_compare);
690 /* DeviceID */
691 size = query_reg_value( hkey, gpu_idW, value, sizeof(buffer) );
692 NtClose( hkey );
693 if (!size || value->Type != REG_SZ || !info->mode_count || !info->modes) return FALSE;
695 if (!(hkey = reg_open_key( enum_key, value_str, value->DataLength - sizeof(WCHAR) )))
696 return FALSE;
698 size = query_reg_subkey_value( hkey, devpropkey_gpu_luidW, sizeof(devpropkey_gpu_luidW), value, sizeof(buffer) );
699 if (size != sizeof(info->gpu_luid))
701 NtClose( hkey );
702 return FALSE;
704 memcpy( &info->gpu_luid, value->Data, sizeof(info->gpu_luid) );
706 size = query_reg_value( hkey, hardware_idW, value, sizeof(buffer) );
707 NtClose( hkey );
708 if (!size || (value->Type != REG_SZ && value->Type != REG_MULTI_SZ))
709 return FALSE;
711 lstrcpyW( info->dev.device_id, value_str );
712 return TRUE;
715 static BOOL read_monitor_settings( struct adapter *adapter, UINT index, struct monitor *monitor )
717 char buffer[4096];
718 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
719 WCHAR *device_name, *value_str = (WCHAR *)value->Data, *ptr;
720 HKEY hkey;
721 DWORD size, len;
723 monitor->flags = adapter->id ? 0 : MONITORINFOF_PRIMARY;
725 /* DeviceName */
726 sprintf( buffer, "\\\\.\\DISPLAY%d\\Monitor%d", adapter->id + 1, index );
727 asciiz_to_unicode( monitor->dev.device_name, buffer );
729 if (!(hkey = reg_open_key( config_key, adapter->config_key,
730 lstrlenW( adapter->config_key ) * sizeof(WCHAR) )))
731 return FALSE;
733 /* Interface name */
734 sprintf( buffer, "MonitorID%u", index );
735 size = query_reg_ascii_value( hkey, buffer, value, sizeof(buffer) );
736 NtClose( hkey );
737 if (!size || value->Type != REG_SZ) return FALSE;
738 len = asciiz_to_unicode( monitor->dev.interface_name, "\\\\\?\\" ) / sizeof(WCHAR) - 1;
739 memcpy( monitor->dev.interface_name + len, value_str, value->DataLength - sizeof(WCHAR) );
740 len += value->DataLength / sizeof(WCHAR) - 1;
741 monitor->dev.interface_name[len++] = '#';
742 memcpy( monitor->dev.interface_name + len, guid_devinterface_monitorW,
743 sizeof(guid_devinterface_monitorW) );
745 /* Replace '\\' with '#' after prefix */
746 for (ptr = monitor->dev.interface_name + ARRAYSIZE("\\\\\?\\") - 1; *ptr; ptr++)
747 if (*ptr == '\\') *ptr = '#';
749 if (!(hkey = reg_open_key( enum_key, value_str, value->DataLength - sizeof(WCHAR) )))
750 return FALSE;
752 /* StateFlags, WINE_DEVPROPKEY_MONITOR_STATEFLAGS */
753 size = query_reg_subkey_value( hkey, wine_devpropkey_monitor_stateflagsW,
754 sizeof(wine_devpropkey_monitor_stateflagsW),
755 value, sizeof(buffer) );
756 if (size != sizeof(monitor->dev.state_flags))
758 NtClose( hkey );
759 return FALSE;
761 monitor->dev.state_flags = *(const DWORD *)value->Data;
763 /* Output ID */
764 size = query_reg_subkey_value( hkey, devpropkey_monitor_output_idW,
765 sizeof(devpropkey_monitor_output_idW),
766 value, sizeof(buffer) );
767 if (size != sizeof(monitor->output_id))
769 NtClose( hkey );
770 return FALSE;
772 monitor->output_id = *(const unsigned int *)value->Data;
774 /* rc_monitor, WINE_DEVPROPKEY_MONITOR_RCMONITOR */
775 size = query_reg_subkey_value( hkey, wine_devpropkey_monitor_rcmonitorW,
776 sizeof(wine_devpropkey_monitor_rcmonitorW),
777 value, sizeof(buffer) );
778 if (size != sizeof(monitor->rc_monitor))
780 NtClose( hkey );
781 return FALSE;
783 monitor->rc_monitor = *(const RECT *)value->Data;
785 /* rc_work, WINE_DEVPROPKEY_MONITOR_RCWORK */
786 size = query_reg_subkey_value( hkey, wine_devpropkey_monitor_rcworkW,
787 sizeof(wine_devpropkey_monitor_rcworkW),
788 value, sizeof(buffer) );
789 if (size != sizeof(monitor->rc_work))
791 NtClose( hkey );
792 return FALSE;
794 monitor->rc_work = *(const RECT *)value->Data;
796 /* DeviceString */
797 if (!query_reg_value( hkey, device_descW, value, sizeof(buffer) ) || value->Type != REG_SZ)
799 NtClose( hkey );
800 return FALSE;
802 memcpy( monitor->dev.device_string, value->Data, value->DataLength );
804 /* DeviceKey */
805 if (!query_reg_value( hkey, driverW, value, sizeof(buffer) ) || value->Type != REG_SZ)
807 NtClose( hkey );
808 return FALSE;
810 size = asciiz_to_unicode( monitor->dev.device_key,
811 "\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\" );
812 device_name = &monitor->dev.device_key[size / sizeof(WCHAR) - 1];
813 memcpy( device_name, value_str, value->DataLength );
815 /* DeviceID */
816 if (!query_reg_value( hkey, hardware_idW, value, sizeof(buffer) ) ||
817 (value->Type != REG_SZ && value->Type != REG_MULTI_SZ))
819 NtClose( hkey );
820 return FALSE;
822 size = lstrlenW( value_str );
823 memcpy( monitor->dev.device_id, value_str, size * sizeof(WCHAR) );
824 monitor->dev.device_id[size++] = '\\';
825 lstrcpyW( monitor->dev.device_id + size, device_name );
827 NtClose( hkey );
828 return TRUE;
831 static void reg_empty_key( HKEY root, const char *key_name )
833 char buffer[4096];
834 KEY_NODE_INFORMATION *key = (KEY_NODE_INFORMATION *)buffer;
835 KEY_VALUE_FULL_INFORMATION *value = (KEY_VALUE_FULL_INFORMATION *)buffer;
836 WCHAR bufferW[512];
837 DWORD size;
838 HKEY hkey;
840 if (key_name)
841 hkey = reg_open_key( root, bufferW, asciiz_to_unicode( bufferW, key_name ) - sizeof(WCHAR) );
842 else
843 hkey = root;
845 while (!NtEnumerateKey( hkey, 0, KeyNodeInformation, key, sizeof(buffer), &size ))
846 reg_delete_tree( hkey, key->Name, key->NameLength );
848 while (!NtEnumerateValueKey( hkey, 0, KeyValueFullInformation, value, sizeof(buffer), &size ))
850 UNICODE_STRING name = { value->NameLength, value->NameLength, value->Name };
851 NtDeleteValueKey( hkey, &name );
854 if (hkey != root) NtClose( hkey );
857 static void prepare_devices(void)
859 char buffer[4096];
860 KEY_NODE_INFORMATION *key = (void *)buffer;
861 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
862 WCHAR *value_str = (WCHAR *)value->Data;
863 WCHAR bufferW[128];
864 unsigned i = 0;
865 DWORD size;
866 HKEY hkey, subkey, device_key, prop_key;
868 if (!enum_key) enum_key = reg_create_key( NULL, enum_keyW, sizeof(enum_keyW), 0, NULL );
869 if (!control_key) control_key = reg_create_key( NULL, control_keyW, sizeof(control_keyW), 0, NULL );
870 if (!video_key) video_key = reg_create_key( NULL, devicemap_video_keyW, sizeof(devicemap_video_keyW),
871 REG_OPTION_VOLATILE, NULL );
873 /* delete monitors */
874 reg_empty_key( enum_key, "DISPLAY\\DEFAULT_MONITOR" );
875 sprintf( buffer, "Class\\%s", guid_devclass_monitorA );
876 hkey = reg_create_key( control_key, bufferW, asciiz_to_unicode( bufferW, buffer ) - sizeof(WCHAR),
877 0, NULL );
878 reg_empty_key( hkey, NULL );
879 set_reg_value( hkey, classW, REG_SZ, monitorW, sizeof(monitorW) );
880 NtClose( hkey );
882 /* delete adapters */
883 reg_empty_key( video_key, NULL );
885 /* clean GPUs */
886 sprintf( buffer, "Class\\%s", guid_devclass_displayA );
887 hkey = reg_create_key( control_key, bufferW, asciiz_to_unicode( bufferW, buffer ) - sizeof(WCHAR),
888 0, NULL );
889 reg_empty_key( hkey, NULL );
890 set_reg_value( hkey, classW, REG_SZ, displayW, sizeof(displayW) );
891 NtClose( hkey );
893 hkey = reg_open_key( enum_key, pciW, sizeof(pciW) );
895 /* To preserve GPU GUIDs, mark them as not present and delete them in cleanup_devices if needed. */
896 while (!NtEnumerateKey( hkey, i++, KeyNodeInformation, key, sizeof(buffer), &size ))
898 unsigned int j = 0;
900 if (!(subkey = reg_open_key( hkey, key->Name, key->NameLength ))) continue;
902 while (!NtEnumerateKey( subkey, j++, KeyNodeInformation, key, sizeof(buffer), &size ))
904 if (!(device_key = reg_open_key( subkey, key->Name, key->NameLength ))) continue;
905 size = query_reg_value( device_key, class_guidW, value, sizeof(buffer) );
906 if (size != sizeof(guid_devclass_displayW) || wcscmp( value_str, guid_devclass_displayW ))
908 NtClose( device_key );
909 continue;
912 size = query_reg_value( device_key, class_guidW, value, sizeof(buffer) );
913 if (size == sizeof(guid_devclass_displayW) &&
914 !wcscmp( (const WCHAR *)value->Data, guid_devclass_displayW ) &&
915 (prop_key = reg_create_key( device_key, devpropkey_device_ispresentW,
916 sizeof(devpropkey_device_ispresentW), 0, NULL )))
918 BOOL present = FALSE;
919 set_reg_value( prop_key, NULL, 0xffff0000 | DEVPROP_TYPE_BOOLEAN,
920 &present, sizeof(present) );
921 NtClose( prop_key );
924 NtClose( device_key );
927 NtClose( subkey );
930 NtClose( hkey );
933 static void cleanup_devices(void)
935 char buffer[4096];
936 KEY_NODE_INFORMATION *key = (void *)buffer;
937 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
938 WCHAR bufferW[512], *value_str = (WCHAR *)value->Data;
939 unsigned i = 0;
940 DWORD size;
941 HKEY hkey, subkey, device_key, prop_key;
943 hkey = reg_open_key( enum_key, pciW, sizeof(pciW) );
945 while (!NtEnumerateKey( hkey, i++, KeyNodeInformation, key, sizeof(buffer), &size ))
947 unsigned int j = 0;
949 if (!(subkey = reg_open_key( hkey, key->Name, key->NameLength ))) continue;
951 while (!NtEnumerateKey( subkey, j++, KeyNodeInformation, key, sizeof(buffer), &size ))
953 BOOL present = FALSE;
955 if (!(device_key = reg_open_key( subkey, key->Name, key->NameLength ))) continue;
956 memcpy( bufferW, key->Name, key->NameLength );
957 bufferW[key->NameLength / sizeof(WCHAR)] = 0;
959 size = query_reg_value( device_key, class_guidW, value, sizeof(buffer) );
960 if (size != sizeof(guid_devclass_displayW) || wcscmp( value_str, guid_devclass_displayW ))
962 NtClose( device_key );
963 continue;
966 if ((prop_key = reg_open_key( device_key, devpropkey_device_ispresentW,
967 sizeof(devpropkey_device_ispresentW) )))
969 if (query_reg_value( prop_key, NULL, value, sizeof(buffer) ) == sizeof(BOOL))
970 present = *(const BOOL *)value->Data;
971 NtClose( prop_key );
974 NtClose( device_key );
976 if (!present && reg_delete_tree( subkey, bufferW, lstrlenW( bufferW ) * sizeof(WCHAR) ))
977 j = 0;
980 NtClose( subkey );
983 NtClose( hkey );
986 /* see UuidCreate */
987 static void uuid_create( GUID *uuid )
989 char buf[4096];
990 NtQuerySystemInformation( SystemInterruptInformation, buf, sizeof(buf), NULL );
991 memcpy( uuid, buf, sizeof(*uuid) );
992 uuid->Data3 &= 0x0fff;
993 uuid->Data3 |= (4 << 12);
994 uuid->Data4[0] &= 0x3f;
995 uuid->Data4[0] |= 0x80;
998 #define TICKSPERSEC 10000000
999 #define SECSPERDAY 86400
1000 #define DAYSPERQUADRICENTENNIUM (365 * 400 + 97)
1001 #define DAYSPERNORMALQUADRENNIUM (365 * 4 + 1)
1003 static unsigned int format_date( WCHAR *bufferW, LONGLONG time )
1005 int cleaps, years, yearday, months, days;
1006 unsigned int day, month, year;
1007 char buffer[32];
1009 days = time / TICKSPERSEC / SECSPERDAY;
1011 /* compute year, month and day of month, see RtlTimeToTimeFields */
1012 cleaps = (3 * ((4 * days + 1227) / DAYSPERQUADRICENTENNIUM) + 3) / 4;
1013 days += 28188 + cleaps;
1014 years = (20 * days - 2442) / (5 * DAYSPERNORMALQUADRENNIUM);
1015 yearday = days - (years * DAYSPERNORMALQUADRENNIUM) / 4;
1016 months = (64 * yearday) / 1959;
1017 if (months < 14)
1019 month = months - 1;
1020 year = years + 1524;
1022 else
1024 month = months - 13;
1025 year = years + 1525;
1027 day = yearday - (1959 * months) / 64 ;
1029 sprintf( buffer, "%u-%u-%u", month, day, year );
1030 return asciiz_to_unicode( bufferW, buffer );
1033 struct device_manager_ctx
1035 unsigned int gpu_count;
1036 unsigned int adapter_count;
1037 unsigned int video_count;
1038 unsigned int monitor_count;
1039 unsigned int output_count;
1040 unsigned int mode_count;
1041 HANDLE mutex;
1042 WCHAR gpuid[128];
1043 WCHAR gpu_guid[64];
1044 LUID gpu_luid;
1045 HKEY adapter_key;
1048 static void link_device( const WCHAR *instance, const WCHAR *class )
1050 unsigned int instance_len = lstrlenW( instance ), len;
1051 unsigned int class_len = lstrlenW( class );
1052 WCHAR buffer[MAX_PATH], *ptr;
1053 HKEY hkey, subkey;
1055 static const WCHAR symbolic_linkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
1056 static const WCHAR hashW[] = {'#'};
1058 len = asciiz_to_unicode( buffer, "DeviceClasses\\" ) / sizeof(WCHAR) - 1;
1059 memcpy( buffer + len, class, class_len * sizeof(WCHAR) );
1060 len += class_len;
1061 len += asciiz_to_unicode( buffer + len, "\\##?#" ) / sizeof(WCHAR) - 1;
1062 memcpy( buffer + len, instance, instance_len * sizeof(WCHAR) );
1063 for (ptr = buffer + len; *ptr; ptr++) if (*ptr == '\\') *ptr = '#';
1064 len += instance_len;
1065 buffer[len++] = '#';
1066 memcpy( buffer + len, class, class_len * sizeof(WCHAR) );
1067 len += class_len;
1068 hkey = reg_create_key( control_key, buffer, len * sizeof(WCHAR), 0, NULL );
1070 set_reg_value( hkey, device_instanceW, REG_SZ, instance, (instance_len + 1) * sizeof(WCHAR) );
1072 subkey = reg_create_key( hkey, hashW, sizeof(hashW), REG_OPTION_VOLATILE, NULL );
1073 NtClose( hkey );
1074 hkey = subkey;
1076 len = asciiz_to_unicode( buffer, "\\\\?\\" ) / sizeof(WCHAR) - 1;
1077 memcpy( buffer + len, instance, (instance_len + 1) * sizeof(WCHAR) );
1078 len += instance_len;
1079 memcpy( buffer + len, class, (class_len + 1) * sizeof(WCHAR) );
1080 len += class_len + 1;
1081 for (ptr = buffer + 4; *ptr; ptr++) if (*ptr == '\\') *ptr = '#';
1082 set_reg_value( hkey, symbolic_linkW, REG_SZ, buffer, len * sizeof(WCHAR) );
1084 if ((subkey = reg_create_key( hkey, controlW, sizeof(controlW), REG_OPTION_VOLATILE, NULL )))
1086 const DWORD linked = 1;
1087 set_reg_value( subkey, linkedW, REG_DWORD, &linked, sizeof(linked) );
1088 NtClose( subkey );
1092 static void add_gpu( const struct gdi_gpu *gpu, void *param )
1094 struct device_manager_ctx *ctx = param;
1095 const WCHAR *desc;
1096 char buffer[4096];
1097 WCHAR bufferW[512];
1098 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
1099 unsigned int gpu_index, size;
1100 HKEY hkey, subkey;
1101 LARGE_INTEGER ft;
1103 static const BOOL present = TRUE;
1104 static const WCHAR wine_adapterW[] = {'W','i','n','e',' ','A','d','a','p','t','e','r',0};
1105 static const WCHAR video_idW[] = {'V','i','d','e','o','I','D',0};
1106 static const WCHAR driver_date_dataW[] =
1107 {'D','r','i','v','e','r','D','a','t','e','D','a','t','a',0};
1108 static const WCHAR adapter_stringW[] =
1109 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n',
1110 '.','A','d','a','p','t','e','r','S','t','r','i','n','g',0};
1111 static const WCHAR bios_stringW[] =
1112 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n','.',
1113 'B','i','o','s','S','t','r','i','n','g',0};
1114 static const WCHAR chip_typeW[] =
1115 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n','.',
1116 'C','h','i','p','T','y','p','e',0};
1117 static const WCHAR dac_typeW[] =
1118 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n','.',
1119 'D','a','c','T','y','p','e',0};
1120 static const WCHAR ramdacW[] =
1121 {'I','n','t','e','r','g','r','a','t','e','d',' ','R','A','M','D','A','C',0};
1122 static const WCHAR driver_dateW[] = {'D','r','i','v','e','r','D','a','t','e',0};
1124 TRACE( "%s %04X %04X %08X %02X\n", debugstr_w(gpu->name),
1125 gpu->vendor_id, gpu->device_id, gpu->subsys_id, gpu->revision_id );
1127 gpu_index = ctx->gpu_count++;
1128 ctx->adapter_count = 0;
1129 ctx->monitor_count = 0;
1130 ctx->mode_count = 0;
1132 if (!enum_key && !(enum_key = reg_create_key( NULL, enum_keyW, sizeof(enum_keyW), 0, NULL )))
1133 return;
1135 if (!ctx->mutex)
1137 ctx->mutex = get_display_device_init_mutex();
1138 pthread_mutex_lock( &display_lock );
1139 prepare_devices();
1142 sprintf( buffer, "PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X\\%08X",
1143 gpu->vendor_id, gpu->device_id, gpu->subsys_id, gpu->revision_id, gpu_index );
1144 size = asciiz_to_unicode( ctx->gpuid, buffer );
1145 if (!(hkey = reg_create_key( enum_key, ctx->gpuid, size - sizeof(WCHAR), 0, NULL ))) return;
1147 set_reg_value( hkey, classW, REG_SZ, displayW, sizeof(displayW) );
1148 set_reg_value( hkey, class_guidW, REG_SZ, guid_devclass_displayW,
1149 sizeof(guid_devclass_displayW) );
1150 sprintf( buffer, "%s\\%04X", guid_devclass_displayA, gpu_index );
1151 set_reg_value( hkey, driverW, REG_SZ, bufferW, asciiz_to_unicode( bufferW, buffer ));
1153 sprintf( buffer, "PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X",
1154 gpu->vendor_id, gpu->device_id, gpu->subsys_id, gpu->revision_id );
1155 size = asciiz_to_unicode( bufferW, buffer );
1156 bufferW[size / sizeof(WCHAR)] = 0; /* for REG_MULTI_SZ */
1157 set_reg_value( hkey, hardware_idW, REG_MULTI_SZ, bufferW, size + sizeof(WCHAR) );
1159 desc = gpu->name;
1160 if (!desc[0]) desc = wine_adapterW;
1161 set_reg_value( hkey, device_descW, REG_SZ, desc, (lstrlenW( desc ) + 1) * sizeof(WCHAR) );
1163 if ((subkey = reg_create_key( hkey, device_parametersW, sizeof(device_parametersW), 0, NULL )))
1165 if (!query_reg_value( subkey, video_idW, value, sizeof(buffer) ))
1167 GUID guid;
1168 uuid_create( &guid );
1169 sprintf( buffer, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
1170 (unsigned int)guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2],
1171 guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7] );
1172 size = asciiz_to_unicode( ctx->gpu_guid, buffer );
1173 TRACE( "created guid %s\n", debugstr_w(ctx->gpu_guid) );
1174 set_reg_value( subkey, video_idW, REG_SZ, ctx->gpu_guid, size );
1176 else
1178 memcpy( ctx->gpu_guid, value->Data, value->DataLength );
1179 TRACE( "got guid %s\n", debugstr_w(ctx->gpu_guid) );
1181 NtClose( subkey );
1184 if ((subkey = reg_create_key( hkey, devpropkey_gpu_vulkan_uuidW,
1185 sizeof(devpropkey_gpu_vulkan_uuidW), 0, NULL )))
1187 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_GUID,
1188 &gpu->vulkan_uuid, sizeof(gpu->vulkan_uuid) );
1189 NtClose( subkey );
1192 if ((subkey = reg_create_key( hkey, devpropkey_device_ispresentW,
1193 sizeof(devpropkey_device_ispresentW), 0, NULL )))
1195 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_BOOLEAN,
1196 &present, sizeof(present) );
1197 NtClose( subkey );
1200 if ((subkey = reg_create_key( hkey, devpropkey_gpu_luidW, sizeof(devpropkey_gpu_luidW), 0, NULL )))
1202 if (query_reg_value( subkey, NULL, value, sizeof(buffer) ) != sizeof(LUID))
1204 NtAllocateLocallyUniqueId( &ctx->gpu_luid );
1205 TRACE("allocated luid %08x%08x\n", (int)ctx->gpu_luid.HighPart, (int)ctx->gpu_luid.LowPart );
1206 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_UINT64,
1207 &ctx->gpu_luid, sizeof(ctx->gpu_luid) );
1209 else
1211 memcpy( &ctx->gpu_luid, value->Data, sizeof(ctx->gpu_luid) );
1212 TRACE("got luid %08x%08x\n", (int)ctx->gpu_luid.HighPart, (int)ctx->gpu_luid.LowPart );
1214 NtClose( subkey );
1217 NtClose( hkey );
1219 sprintf( buffer, "Class\\%s\\%04X", guid_devclass_displayA, gpu_index );
1220 hkey = reg_create_key( control_key, bufferW,
1221 asciiz_to_unicode( bufferW, buffer ) - sizeof(WCHAR), 0, NULL );
1223 NtQuerySystemTime( &ft );
1224 set_reg_value( hkey, driver_dateW, REG_SZ, bufferW, format_date( bufferW, ft.QuadPart ));
1226 set_reg_value( hkey, driver_date_dataW, REG_BINARY, &ft, sizeof(ft) );
1228 size = (lstrlenW( desc ) + 1) * sizeof(WCHAR);
1229 set_reg_value( hkey, driver_descW, REG_SZ, desc, size );
1230 set_reg_value( hkey, adapter_stringW, REG_BINARY, desc, size );
1231 set_reg_value( hkey, bios_stringW, REG_BINARY, desc, size );
1232 set_reg_value( hkey, chip_typeW, REG_BINARY, desc, size );
1233 set_reg_value( hkey, dac_typeW, REG_BINARY, ramdacW, sizeof(ramdacW) );
1235 NtClose( hkey );
1237 link_device( ctx->gpuid, guid_devinterface_display_adapterW );
1238 link_device( ctx->gpuid, guid_display_device_arrivalW );
1241 static void add_adapter( const struct gdi_adapter *adapter, void *param )
1243 struct device_manager_ctx *ctx = param;
1244 unsigned int adapter_index, video_index, len;
1245 char name[64], buffer[MAX_PATH];
1246 WCHAR nameW[64], bufferW[MAX_PATH];
1247 HKEY hkey;
1249 TRACE( "\n" );
1251 if (ctx->adapter_key)
1253 NtClose( ctx->adapter_key );
1254 ctx->adapter_key = NULL;
1257 adapter_index = ctx->adapter_count++;
1258 video_index = ctx->video_count++;
1259 ctx->monitor_count = 0;
1260 ctx->mode_count = 0;
1262 len = asciiz_to_unicode( bufferW, "\\Registry\\Machine\\System\\CurrentControlSet\\"
1263 "Control\\Video\\" ) / sizeof(WCHAR) - 1;
1264 lstrcpyW( bufferW + len, ctx->gpu_guid );
1265 len += lstrlenW( bufferW + len );
1266 sprintf( buffer, "\\%04x", adapter_index );
1267 len += asciiz_to_unicode( bufferW + len, buffer ) / sizeof(WCHAR) - 1;
1268 hkey = reg_create_key( NULL, bufferW, len * sizeof(WCHAR),
1269 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK, NULL );
1270 if (!hkey) hkey = reg_create_key( NULL, bufferW, len * sizeof(WCHAR),
1271 REG_OPTION_VOLATILE | REG_OPTION_OPEN_LINK, NULL );
1273 sprintf( name, "\\Device\\Video%u", video_index );
1274 asciiz_to_unicode( nameW, name );
1275 set_reg_value( video_key, nameW, REG_SZ, bufferW, (lstrlenW( bufferW ) + 1) * sizeof(WCHAR) );
1277 if (hkey)
1279 sprintf( buffer, "\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\"
1280 "%s\\%04X", guid_devclass_displayA, ctx->gpu_count - 1 );
1281 len = asciiz_to_unicode( bufferW, buffer ) - sizeof(WCHAR);
1282 set_reg_value( hkey, symbolic_link_valueW, REG_LINK, bufferW, len );
1283 NtClose( hkey );
1285 else ERR( "failed to create link key\n" );
1287 /* Following information is Wine specific, it doesn't really exist on Windows. */
1288 len = asciiz_to_unicode( bufferW, "System\\CurrentControlSet\\Control\\Video\\" )
1289 / sizeof(WCHAR) - 1;
1290 lstrcpyW( bufferW + len, ctx->gpu_guid );
1291 len += lstrlenW( bufferW + len );
1292 sprintf( buffer, "\\%04x", adapter_index );
1293 len += asciiz_to_unicode( bufferW + len, buffer ) / sizeof(WCHAR) - 1;
1294 ctx->adapter_key = reg_create_key( config_key, bufferW, len * sizeof(WCHAR),
1295 REG_OPTION_VOLATILE, NULL );
1297 set_reg_value( ctx->adapter_key, gpu_idW, REG_SZ, ctx->gpuid,
1298 (lstrlenW( ctx->gpuid ) + 1) * sizeof(WCHAR) );
1299 set_reg_value( ctx->adapter_key, state_flagsW, REG_DWORD, &adapter->state_flags,
1300 sizeof(adapter->state_flags) );
1303 static void add_monitor( const struct gdi_monitor *monitor, void *param )
1305 struct device_manager_ctx *ctx = param;
1306 char buffer[MAX_PATH], instance[64];
1307 unsigned int monitor_index, output_index;
1308 WCHAR bufferW[MAX_PATH];
1309 HKEY hkey, subkey;
1311 static const WCHAR default_monitorW[] =
1312 {'M','O','N','I','T','O','R','\\','D','e','f','a','u','l','t','_','M','o','n','i','t','o','r',0,0};
1314 TRACE( "%s %s %s\n", debugstr_w(monitor->name), wine_dbgstr_rect(&monitor->rc_monitor),
1315 wine_dbgstr_rect(&monitor->rc_work) );
1317 monitor_index = ctx->monitor_count++;
1318 output_index = ctx->output_count++;
1320 sprintf( buffer, "MonitorID%u", monitor_index );
1321 sprintf( instance, "DISPLAY\\Default_Monitor\\%04X&%04X", ctx->video_count - 1, monitor_index );
1322 set_reg_ascii_value( ctx->adapter_key, buffer, instance );
1324 hkey = reg_create_key( enum_key, bufferW, asciiz_to_unicode( bufferW, instance ) - sizeof(WCHAR),
1325 0, NULL );
1326 if (!hkey) return;
1328 link_device( bufferW, guid_devinterface_monitorW );
1330 lstrcpyW( bufferW, monitor->name );
1331 if (!bufferW[0]) asciiz_to_unicode( bufferW, "Generic Non-PnP Monitor" );
1332 set_reg_value( hkey, device_descW, REG_SZ, bufferW, (lstrlenW( bufferW ) + 1) * sizeof(WCHAR) );
1334 set_reg_value( hkey, classW, REG_SZ, monitorW, sizeof(monitorW) );
1335 sprintf( buffer, "%s\\%04X", guid_devclass_monitorA, output_index );
1336 set_reg_ascii_value( hkey, "Driver", buffer );
1337 set_reg_value( hkey, class_guidW, REG_SZ, guid_devclass_monitorW, sizeof(guid_devclass_monitorW) );
1338 set_reg_value( hkey, hardware_idW, REG_MULTI_SZ, default_monitorW, sizeof(default_monitorW) );
1340 if ((subkey = reg_create_key( hkey, device_parametersW, sizeof(device_parametersW), 0, NULL )))
1342 static const WCHAR bad_edidW[] = {'B','A','D','_','E','D','I','D',0};
1343 static const WCHAR edidW[] = {'E','D','I','D',0};
1345 if (monitor->edid_len)
1346 set_reg_value( subkey, edidW, REG_BINARY, monitor->edid, monitor->edid_len );
1347 else
1348 set_reg_value( subkey, bad_edidW, REG_BINARY, NULL, 0 );
1349 NtClose( subkey );
1352 /* StateFlags */
1353 if ((subkey = reg_create_key( hkey, wine_devpropkey_monitor_stateflagsW,
1354 sizeof(wine_devpropkey_monitor_stateflagsW), 0, NULL )))
1356 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_UINT32, &monitor->state_flags,
1357 sizeof(monitor->state_flags) );
1358 NtClose( subkey );
1361 /* WINE_DEVPROPKEY_MONITOR_RCMONITOR */
1362 if ((subkey = reg_create_key( hkey, wine_devpropkey_monitor_rcmonitorW,
1363 sizeof(wine_devpropkey_monitor_rcmonitorW), 0, NULL )))
1365 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_BINARY, &monitor->rc_monitor,
1366 sizeof(monitor->rc_monitor) );
1367 NtClose( subkey );
1370 /* WINE_DEVPROPKEY_MONITOR_RCWORK */
1371 if ((subkey = reg_create_key( hkey, wine_devpropkey_monitor_rcworkW,
1372 sizeof(wine_devpropkey_monitor_rcworkW), 0, NULL )))
1374 TRACE( "rc_work %s\n", wine_dbgstr_rect(&monitor->rc_work) );
1375 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_BINARY, &monitor->rc_work,
1376 sizeof(monitor->rc_work) );
1377 NtClose( subkey );
1380 /* WINE_DEVPROPKEY_MONITOR_ADAPTERNAME */
1381 if ((subkey = reg_create_key( hkey, wine_devpropkey_monitor_adapternameW,
1382 sizeof(wine_devpropkey_monitor_adapternameW), 0, NULL )))
1384 sprintf( buffer, "\\\\.\\DISPLAY%u", ctx->video_count );
1385 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_STRING, bufferW,
1386 asciiz_to_unicode( bufferW, buffer ));
1387 NtClose( subkey );
1390 /* DEVPROPKEY_MONITOR_GPU_LUID */
1391 if ((subkey = reg_create_key( hkey, devpropkey_monitor_gpu_luidW,
1392 sizeof(devpropkey_monitor_gpu_luidW), 0, NULL )))
1394 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_INT64,
1395 &ctx->gpu_luid, sizeof(ctx->gpu_luid) );
1396 NtClose( subkey );
1399 /* DEVPROPKEY_MONITOR_OUTPUT_ID */
1400 if ((subkey = reg_create_key( hkey, devpropkey_monitor_output_idW,
1401 sizeof(devpropkey_monitor_output_idW), 0, NULL )))
1403 set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_UINT32,
1404 &output_index, sizeof(output_index) );
1405 NtClose( subkey );
1408 NtClose( hkey );
1410 sprintf( buffer, "Class\\%s\\%04X", guid_devclass_monitorA, output_index );
1411 hkey = reg_create_key( control_key, bufferW,
1412 asciiz_to_unicode( bufferW, buffer ) - sizeof(WCHAR), 0, NULL );
1413 if (hkey) NtClose( hkey );
1416 static void add_mode( const DEVMODEW *mode, void *param )
1418 struct device_manager_ctx *ctx = param;
1420 if (!ctx->adapter_count)
1422 static const struct gdi_adapter default_adapter =
1424 .state_flags = DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_PRIMARY_DEVICE | DISPLAY_DEVICE_VGA_COMPATIBLE,
1426 TRACE( "adding default fake adapter\n" );
1427 add_adapter( &default_adapter, ctx );
1430 if (write_adapter_mode( ctx->adapter_key, ctx->mode_count, mode ))
1432 ctx->mode_count++;
1433 set_reg_value( ctx->adapter_key, mode_countW, REG_DWORD, &ctx->mode_count, sizeof(ctx->mode_count) );
1437 static const struct gdi_device_manager device_manager =
1439 add_gpu,
1440 add_adapter,
1441 add_monitor,
1442 add_mode,
1445 static void release_display_manager_ctx( struct device_manager_ctx *ctx )
1447 if (ctx->mutex)
1449 pthread_mutex_unlock( &display_lock );
1450 release_display_device_init_mutex( ctx->mutex );
1452 if (ctx->adapter_key)
1454 NtClose( ctx->adapter_key );
1455 last_query_display_time = 0;
1457 if (ctx->gpu_count) cleanup_devices();
1460 static void clear_display_devices(void)
1462 struct adapter *adapter;
1463 struct monitor *monitor;
1465 if (list_head( &monitors ) == &virtual_monitor.entry)
1467 list_init( &monitors );
1468 return;
1471 while (!list_empty( &monitors ))
1473 monitor = LIST_ENTRY( list_head( &monitors ), struct monitor, entry );
1474 adapter_release( monitor->adapter );
1475 list_remove( &monitor->entry );
1476 free( monitor );
1479 while (!list_empty( &adapters ))
1481 adapter = LIST_ENTRY( list_head( &adapters ), struct adapter, entry );
1482 list_remove( &adapter->entry );
1483 adapter_release( adapter );
1487 static BOOL update_display_cache_from_registry(void)
1489 DWORD adapter_id, monitor_id, monitor_count = 0, size;
1490 KEY_BASIC_INFORMATION key;
1491 struct adapter *adapter;
1492 struct monitor *monitor, *monitor2;
1493 HANDLE mutex = NULL;
1494 NTSTATUS status;
1495 BOOL ret;
1497 /* If user driver did initialize the registry, then exit */
1498 if (!video_key && !(video_key = reg_open_key( NULL, devicemap_video_keyW,
1499 sizeof(devicemap_video_keyW) )))
1500 return FALSE;
1502 status = NtQueryKey( video_key, KeyBasicInformation, &key,
1503 offsetof(KEY_BASIC_INFORMATION, Name), &size );
1504 if (status && status != STATUS_BUFFER_OVERFLOW)
1505 return FALSE;
1507 if (key.LastWriteTime.QuadPart <= last_query_display_time) return TRUE;
1509 mutex = get_display_device_init_mutex();
1510 pthread_mutex_lock( &display_lock );
1512 clear_display_devices();
1514 for (adapter_id = 0;; adapter_id++)
1516 if (!(adapter = calloc( 1, sizeof(*adapter) ))) break;
1517 adapter->refcount = 1;
1518 adapter->id = adapter_id;
1520 if (!read_display_adapter_settings( adapter_id, adapter ))
1522 adapter_release( adapter );
1523 break;
1526 list_add_tail( &adapters, &adapter->entry );
1527 for (monitor_id = 0;; monitor_id++)
1529 if (!(monitor = calloc( 1, sizeof(*monitor) ))) break;
1530 if (!read_monitor_settings( adapter, monitor_id, monitor ))
1532 free( monitor );
1533 break;
1536 monitor->id = monitor_id;
1537 monitor->adapter = adapter_acquire( adapter );
1539 LIST_FOR_EACH_ENTRY(monitor2, &monitors, struct monitor, entry)
1541 if (EqualRect(&monitor2->rc_monitor, &monitor->rc_monitor))
1543 monitor->is_clone = TRUE;
1544 break;
1548 monitor->handle = UlongToHandle( ++monitor_count );
1549 list_add_tail( &monitors, &monitor->entry );
1553 if ((ret = !list_empty( &adapters ) && !list_empty( &monitors )))
1554 last_query_display_time = key.LastWriteTime.QuadPart;
1555 pthread_mutex_unlock( &display_lock );
1556 release_display_device_init_mutex( mutex );
1557 return ret;
1560 static BOOL update_display_cache( BOOL force )
1562 HWINSTA winstation = NtUserGetProcessWindowStation();
1563 struct device_manager_ctx ctx = {0};
1564 USEROBJECTFLAGS flags;
1566 /* services do not have any adapters, only a virtual monitor */
1567 if (NtUserGetObjectInformation( winstation, UOI_FLAGS, &flags, sizeof(flags), NULL )
1568 && !(flags.dwFlags & WSF_VISIBLE))
1570 pthread_mutex_lock( &display_lock );
1571 clear_display_devices();
1572 list_add_tail( &monitors, &virtual_monitor.entry );
1573 pthread_mutex_unlock( &display_lock );
1574 return TRUE;
1577 if (!user_driver->pUpdateDisplayDevices( &device_manager, force, &ctx ) && force)
1579 /* default implementation: expose an adapter and a monitor with a few standard modes,
1580 * and read / write current display settings from / to the registry.
1582 static const DEVMODEW modes[] =
1584 { .dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY,
1585 .dmBitsPerPel = 32, .dmPelsWidth = 640, .dmPelsHeight = 480, .dmDisplayFrequency = 60, },
1586 { .dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY,
1587 .dmBitsPerPel = 32, .dmPelsWidth = 800, .dmPelsHeight = 600, .dmDisplayFrequency = 60, },
1588 { .dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY,
1589 .dmBitsPerPel = 32, .dmPelsWidth = 1024, .dmPelsHeight = 768, .dmDisplayFrequency = 60, },
1590 { .dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY,
1591 .dmBitsPerPel = 16, .dmPelsWidth = 640, .dmPelsHeight = 480, .dmDisplayFrequency = 60, },
1592 { .dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY,
1593 .dmBitsPerPel = 16, .dmPelsWidth = 800, .dmPelsHeight = 600, .dmDisplayFrequency = 60, },
1594 { .dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY,
1595 .dmBitsPerPel = 16, .dmPelsWidth = 1024, .dmPelsHeight = 768, .dmDisplayFrequency = 60, },
1597 static const struct gdi_gpu gpu;
1598 static const struct gdi_adapter adapter =
1600 .state_flags = DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_PRIMARY_DEVICE | DISPLAY_DEVICE_VGA_COMPATIBLE,
1602 struct gdi_monitor monitor =
1604 .state_flags = DISPLAY_DEVICE_ACTIVE | DISPLAY_DEVICE_ATTACHED,
1606 DEVMODEW mode = {{0}};
1607 UINT i;
1609 add_gpu( &gpu, &ctx );
1610 add_adapter( &adapter, &ctx );
1612 if (!read_adapter_mode( ctx.adapter_key, ENUM_CURRENT_SETTINGS, &mode ))
1614 mode = modes[2];
1615 mode.dmFields |= DM_POSITION;
1616 write_adapter_mode( ctx.adapter_key, ENUM_CURRENT_SETTINGS, &mode );
1618 monitor.rc_monitor.right = mode.dmPelsWidth;
1619 monitor.rc_monitor.bottom = mode.dmPelsHeight;
1620 monitor.rc_work.right = mode.dmPelsWidth;
1621 monitor.rc_work.bottom = mode.dmPelsHeight;
1623 add_monitor( &monitor, &ctx );
1624 for (i = 0; i < ARRAY_SIZE(modes); ++i) add_mode( modes + i, &ctx );
1626 release_display_manager_ctx( &ctx );
1628 if (!update_display_cache_from_registry())
1630 if (force)
1632 ERR( "Failed to read display config.\n" );
1633 return FALSE;
1636 if (ctx.gpu_count)
1638 ERR( "Driver reported devices, but we failed to read them.\n" );
1639 return FALSE;
1642 return update_display_cache( TRUE );
1645 return TRUE;
1648 static BOOL lock_display_devices(void)
1650 if (!update_display_cache( FALSE )) return FALSE;
1651 pthread_mutex_lock( &display_lock );
1652 return TRUE;
1655 static void unlock_display_devices(void)
1657 pthread_mutex_unlock( &display_lock );
1660 static HDC get_display_dc(void)
1662 pthread_mutex_lock( &display_dc_lock );
1663 if (!display_dc)
1665 HDC dc;
1667 pthread_mutex_unlock( &display_dc_lock );
1668 dc = NtGdiOpenDCW( NULL, NULL, NULL, 0, TRUE, NULL, NULL, NULL );
1669 pthread_mutex_lock( &display_dc_lock );
1670 if (display_dc)
1671 NtGdiDeleteObjectApp( dc );
1672 else
1673 display_dc = dc;
1675 return display_dc;
1678 static void release_display_dc( HDC hdc )
1680 pthread_mutex_unlock( &display_dc_lock );
1683 /**********************************************************************
1684 * get_monitor_dpi
1686 UINT get_monitor_dpi( HMONITOR monitor )
1688 /* FIXME: use the monitor DPI instead */
1689 return system_dpi;
1692 /**********************************************************************
1693 * get_win_monitor_dpi
1695 UINT get_win_monitor_dpi( HWND hwnd )
1697 /* FIXME: use the monitor DPI instead */
1698 return system_dpi;
1701 /**********************************************************************
1702 * get_thread_dpi_awareness
1704 DPI_AWARENESS get_thread_dpi_awareness(void)
1706 struct ntuser_thread_info *info = NtUserGetThreadInfo();
1707 ULONG_PTR context = info->dpi_awareness;
1709 if (!context) context = NtUserGetProcessDpiAwarenessContext( NULL );
1711 switch (context)
1713 case 0x10:
1714 case 0x11:
1715 case 0x12:
1716 case 0x80000010:
1717 case 0x80000011:
1718 case 0x80000012:
1719 return context & 3;
1720 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE:
1721 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE:
1722 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE:
1723 return ~context;
1724 default:
1725 return DPI_AWARENESS_INVALID;
1729 DWORD get_process_layout(void)
1731 return process_layout == ~0u ? 0 : process_layout;
1734 /**********************************************************************
1735 * get_thread_dpi
1737 UINT get_thread_dpi(void)
1739 switch (get_thread_dpi_awareness())
1741 case DPI_AWARENESS_UNAWARE: return USER_DEFAULT_SCREEN_DPI;
1742 case DPI_AWARENESS_SYSTEM_AWARE: return system_dpi;
1743 default: return 0; /* no scaling */
1747 /* see GetDpiForSystem */
1748 UINT get_system_dpi(void)
1750 if (get_thread_dpi_awareness() == DPI_AWARENESS_UNAWARE) return USER_DEFAULT_SCREEN_DPI;
1751 return system_dpi;
1754 /* see GetAwarenessFromDpiAwarenessContext */
1755 static DPI_AWARENESS get_awareness_from_dpi_awareness_context( DPI_AWARENESS_CONTEXT context )
1757 switch ((ULONG_PTR)context)
1759 case 0x10:
1760 case 0x11:
1761 case 0x12:
1762 case 0x80000010:
1763 case 0x80000011:
1764 case 0x80000012:
1765 return (ULONG_PTR)context & 3;
1766 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE:
1767 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE:
1768 case (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE:
1769 return ~(ULONG_PTR)context;
1770 default:
1771 return DPI_AWARENESS_INVALID;
1775 /**********************************************************************
1776 * SetThreadDpiAwarenessContext (win32u.so)
1778 DPI_AWARENESS_CONTEXT WINAPI SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT context )
1780 struct ntuser_thread_info *info = NtUserGetThreadInfo();
1781 DPI_AWARENESS prev, val = get_awareness_from_dpi_awareness_context( context );
1783 if (val == DPI_AWARENESS_INVALID)
1785 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
1786 return 0;
1788 if (!(prev = info->dpi_awareness))
1790 prev = NtUserGetProcessDpiAwarenessContext( GetCurrentProcess() ) & 3;
1791 prev |= 0x80000010; /* restore to process default */
1793 if (((ULONG_PTR)context & ~(ULONG_PTR)0x13) == 0x80000000) info->dpi_awareness = 0;
1794 else info->dpi_awareness = val | 0x10;
1795 return ULongToHandle( prev );
1798 /**********************************************************************
1799 * map_dpi_rect
1801 RECT map_dpi_rect( RECT rect, UINT dpi_from, UINT dpi_to )
1803 if (dpi_from && dpi_to && dpi_from != dpi_to)
1805 rect.left = muldiv( rect.left, dpi_to, dpi_from );
1806 rect.top = muldiv( rect.top, dpi_to, dpi_from );
1807 rect.right = muldiv( rect.right, dpi_to, dpi_from );
1808 rect.bottom = muldiv( rect.bottom, dpi_to, dpi_from );
1810 return rect;
1813 /**********************************************************************
1814 * map_dpi_point
1816 POINT map_dpi_point( POINT pt, UINT dpi_from, UINT dpi_to )
1818 if (dpi_from && dpi_to && dpi_from != dpi_to)
1820 pt.x = muldiv( pt.x, dpi_to, dpi_from );
1821 pt.y = muldiv( pt.y, dpi_to, dpi_from );
1823 return pt;
1826 /**********************************************************************
1827 * point_win_to_phys_dpi
1829 static POINT point_win_to_phys_dpi( HWND hwnd, POINT pt )
1831 return map_dpi_point( pt, get_dpi_for_window( hwnd ), get_win_monitor_dpi( hwnd ) );
1834 /**********************************************************************
1835 * point_phys_to_win_dpi
1837 POINT point_phys_to_win_dpi( HWND hwnd, POINT pt )
1839 return map_dpi_point( pt, get_win_monitor_dpi( hwnd ), get_dpi_for_window( hwnd ));
1842 /**********************************************************************
1843 * point_thread_to_win_dpi
1845 POINT point_thread_to_win_dpi( HWND hwnd, POINT pt )
1847 UINT dpi = get_thread_dpi();
1848 if (!dpi) dpi = get_win_monitor_dpi( hwnd );
1849 return map_dpi_point( pt, dpi, get_dpi_for_window( hwnd ));
1852 /**********************************************************************
1853 * rect_thread_to_win_dpi
1855 RECT rect_thread_to_win_dpi( HWND hwnd, RECT rect )
1857 UINT dpi = get_thread_dpi();
1858 if (!dpi) dpi = get_win_monitor_dpi( hwnd );
1859 return map_dpi_rect( rect, dpi, get_dpi_for_window( hwnd ) );
1862 /* map value from system dpi to standard 96 dpi for storing in the registry */
1863 static int map_from_system_dpi( int val )
1865 return muldiv( val, USER_DEFAULT_SCREEN_DPI, get_system_dpi() );
1868 /* map value from 96 dpi to system or custom dpi */
1869 static int map_to_dpi( int val, UINT dpi )
1871 if (!dpi) dpi = get_system_dpi();
1872 return muldiv( val, dpi, USER_DEFAULT_SCREEN_DPI );
1875 RECT get_virtual_screen_rect( UINT dpi )
1877 struct monitor *monitor;
1878 RECT rect = {0};
1880 if (!lock_display_devices()) return rect;
1882 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
1884 union_rect( &rect, &rect, &monitor->rc_monitor );
1887 unlock_display_devices();
1889 if (dpi) rect = map_dpi_rect( rect, system_dpi, dpi );
1890 return rect;
1893 static BOOL is_window_rect_full_screen( const RECT *rect )
1895 struct monitor *monitor;
1896 BOOL ret = FALSE;
1898 if (!lock_display_devices()) return FALSE;
1900 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
1902 if (!(monitor->dev.state_flags & DISPLAY_DEVICE_ACTIVE))
1903 continue;
1905 if (rect->left <= monitor->rc_monitor.left && rect->right >= monitor->rc_monitor.right &&
1906 rect->top <= monitor->rc_monitor.top && rect->bottom >= monitor->rc_monitor.bottom)
1908 ret = TRUE;
1909 break;
1913 unlock_display_devices();
1914 return ret;
1917 RECT get_display_rect( const WCHAR *display )
1919 struct monitor *monitor;
1920 RECT rect = {0};
1922 if (!lock_display_devices()) return rect;
1924 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
1926 if (!monitor->adapter || wcsicmp( monitor->adapter->dev.device_name, display )) continue;
1927 rect = monitor->rc_monitor;
1928 break;
1931 unlock_display_devices();
1932 return map_dpi_rect( rect, system_dpi, get_thread_dpi() );
1935 RECT get_primary_monitor_rect( UINT dpi )
1937 struct monitor *monitor;
1938 RECT rect = {0};
1940 if (!lock_display_devices()) return rect;
1942 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
1944 if (!(monitor->flags & MONITORINFOF_PRIMARY)) continue;
1945 rect = monitor->rc_monitor;
1946 break;
1949 unlock_display_devices();
1950 return map_dpi_rect( rect, system_dpi, dpi );
1953 /**********************************************************************
1954 * NtUserGetDisplayConfigBufferSizes (win32u.@)
1956 LONG WINAPI NtUserGetDisplayConfigBufferSizes( UINT32 flags, UINT32 *num_path_info,
1957 UINT32 *num_mode_info )
1959 struct monitor *monitor;
1960 UINT32 count = 0;
1962 TRACE( "(0x%x %p %p)\n", flags, num_path_info, num_mode_info );
1964 if (!num_path_info || !num_mode_info)
1965 return ERROR_INVALID_PARAMETER;
1967 *num_path_info = 0;
1969 switch (flags)
1971 case QDC_ALL_PATHS:
1972 case QDC_ONLY_ACTIVE_PATHS:
1973 case QDC_DATABASE_CURRENT:
1974 break;
1975 default:
1976 return ERROR_INVALID_PARAMETER;
1979 /* FIXME: semi-stub */
1980 if (flags != QDC_ONLY_ACTIVE_PATHS)
1981 FIXME( "only returning active paths\n" );
1983 if (lock_display_devices())
1985 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
1987 if (!(monitor->dev.state_flags & DISPLAY_DEVICE_ACTIVE))
1988 continue;
1989 count++;
1991 unlock_display_devices();
1994 *num_path_info = count;
1995 *num_mode_info = count * 2;
1996 TRACE( "returning %u paths %u modes\n", *num_path_info, *num_mode_info );
1997 return ERROR_SUCCESS;
2000 /* display_lock mutex must be held */
2001 static struct display_device *find_monitor_device( struct display_device *adapter, UINT index )
2003 struct monitor *monitor;
2005 LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry)
2006 if (&monitor->adapter->dev == adapter && index == monitor->id)
2007 return &monitor->dev;
2009 WARN( "Failed to find adapter %s monitor with id %u.\n", debugstr_w(adapter->device_name), index );
2010 return NULL;
2013 /* display_lock mutex must be held */
2014 static struct display_device *find_adapter_device_by_id( UINT index )
2016 struct adapter *adapter;
2018 LIST_FOR_EACH_ENTRY(adapter, &adapters, struct adapter, entry)
2019 if (index == adapter->id) return &adapter->dev;
2021 WARN( "Failed to find adapter with id %u.\n", index );
2022 return NULL;
2025 /* display_lock mutex must be held */
2026 static struct display_device *find_adapter_device_by_name( UNICODE_STRING *name )
2028 SIZE_T len = name->Length / sizeof(WCHAR);
2029 struct adapter *adapter;
2031 LIST_FOR_EACH_ENTRY(adapter, &adapters, struct adapter, entry)
2032 if (!wcsnicmp( name->Buffer, adapter->dev.device_name, len ) && !adapter->dev.device_name[len])
2033 return &adapter->dev;
2035 WARN( "Failed to find adapter with name %s.\n", debugstr_us(name) );
2036 return NULL;
2039 /* Find and acquire the adapter matching name, or primary adapter if name is NULL.
2040 * If not NULL, the returned adapter needs to be released with adapter_release.
2042 static struct adapter *find_adapter( UNICODE_STRING *name )
2044 struct display_device *device;
2045 struct adapter *adapter;
2047 if (!lock_display_devices()) return NULL;
2049 if (name && name->Length) device = find_adapter_device_by_name( name );
2050 else device = find_adapter_device_by_id( 0 ); /* use primary adapter */
2052 if (!device) adapter = NULL;
2053 else adapter = adapter_acquire( CONTAINING_RECORD( device, struct adapter, dev ) );
2055 unlock_display_devices();
2056 return adapter;
2059 /***********************************************************************
2060 * NtUserEnumDisplayDevices (win32u.@)
2062 NTSTATUS WINAPI NtUserEnumDisplayDevices( UNICODE_STRING *device, DWORD index,
2063 DISPLAY_DEVICEW *info, DWORD flags )
2065 struct display_device *found = NULL;
2067 TRACE( "%s %u %p %#x\n", debugstr_us( device ), (int)index, info, (int)flags );
2069 if (!info || !info->cb) return STATUS_UNSUCCESSFUL;
2071 if (!lock_display_devices()) return STATUS_UNSUCCESSFUL;
2073 if (!device || !device->Length) found = find_adapter_device_by_id( index );
2074 else if ((found = find_adapter_device_by_name( device ))) found = find_monitor_device( found, index );
2076 if (found)
2078 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceName) + sizeof(info->DeviceName))
2079 lstrcpyW( info->DeviceName, found->device_name );
2080 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceString) + sizeof(info->DeviceString))
2081 lstrcpyW( info->DeviceString, found->device_string );
2082 if (info->cb >= offsetof(DISPLAY_DEVICEW, StateFlags) + sizeof(info->StateFlags))
2083 info->StateFlags = found->state_flags;
2084 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->DeviceID))
2085 lstrcpyW( info->DeviceID, (flags & EDD_GET_DEVICE_INTERFACE_NAME)
2086 ? found->interface_name : found->device_id );
2087 if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(info->DeviceKey))
2088 lstrcpyW( info->DeviceKey, found->device_key );
2090 unlock_display_devices();
2091 return found ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
2094 #define _X_FIELD(prefix, bits) \
2095 if ((fields) & prefix##_##bits) \
2097 p += sprintf( p, "%s%s", first ? "" : ",", #bits ); \
2098 first = FALSE; \
2101 static const char *_CDS_flags( DWORD fields )
2103 BOOL first = TRUE;
2104 CHAR buf[128];
2105 CHAR *p = buf;
2107 _X_FIELD(CDS, UPDATEREGISTRY)
2108 _X_FIELD(CDS, TEST)
2109 _X_FIELD(CDS, FULLSCREEN)
2110 _X_FIELD(CDS, GLOBAL)
2111 _X_FIELD(CDS, SET_PRIMARY)
2112 _X_FIELD(CDS, VIDEOPARAMETERS)
2113 _X_FIELD(CDS, ENABLE_UNSAFE_MODES)
2114 _X_FIELD(CDS, DISABLE_UNSAFE_MODES)
2115 _X_FIELD(CDS, RESET)
2116 _X_FIELD(CDS, RESET_EX)
2117 _X_FIELD(CDS, NORESET)
2119 *p = 0;
2120 return wine_dbg_sprintf( "%s", buf );
2123 static const char *_DM_fields( DWORD fields )
2125 BOOL first = TRUE;
2126 CHAR buf[128];
2127 CHAR *p = buf;
2129 _X_FIELD(DM, BITSPERPEL)
2130 _X_FIELD(DM, PELSWIDTH)
2131 _X_FIELD(DM, PELSHEIGHT)
2132 _X_FIELD(DM, DISPLAYFLAGS)
2133 _X_FIELD(DM, DISPLAYFREQUENCY)
2134 _X_FIELD(DM, POSITION)
2135 _X_FIELD(DM, DISPLAYORIENTATION)
2137 *p = 0;
2138 return wine_dbg_sprintf( "%s", buf );
2141 #undef _X_FIELD
2143 static void trace_devmode( const DEVMODEW *devmode )
2145 TRACE( "dmFields=%s ", _DM_fields(devmode->dmFields) );
2146 if (devmode->dmFields & DM_BITSPERPEL)
2147 TRACE( "dmBitsPerPel=%u ", (int)devmode->dmBitsPerPel );
2148 if (devmode->dmFields & DM_PELSWIDTH)
2149 TRACE( "dmPelsWidth=%u ", (int)devmode->dmPelsWidth );
2150 if (devmode->dmFields & DM_PELSHEIGHT)
2151 TRACE( "dmPelsHeight=%u ", (int)devmode->dmPelsHeight );
2152 if (devmode->dmFields & DM_DISPLAYFREQUENCY)
2153 TRACE( "dmDisplayFrequency=%u ", (int)devmode->dmDisplayFrequency );
2154 if (devmode->dmFields & DM_POSITION)
2155 TRACE( "dmPosition=(%d,%d) ", (int)devmode->dmPosition.x, (int)devmode->dmPosition.y );
2156 if (devmode->dmFields & DM_DISPLAYFLAGS)
2157 TRACE( "dmDisplayFlags=%#x ", (int)devmode->dmDisplayFlags );
2158 if (devmode->dmFields & DM_DISPLAYORIENTATION)
2159 TRACE( "dmDisplayOrientation=%u ", (int)devmode->dmDisplayOrientation );
2160 TRACE("\n");
2163 static BOOL is_detached_mode( const DEVMODEW *mode )
2165 return mode->dmFields & DM_POSITION &&
2166 mode->dmFields & DM_PELSWIDTH &&
2167 mode->dmFields & DM_PELSHEIGHT &&
2168 mode->dmPelsWidth == 0 &&
2169 mode->dmPelsHeight == 0;
2172 static const DEVMODEW *find_display_mode( const DEVMODEW *modes, DEVMODEW *devmode )
2174 const DEVMODEW *mode;
2176 if (is_detached_mode( devmode )) return devmode;
2178 for (mode = modes; mode && mode->dmSize; mode = NEXT_DEVMODEW(mode))
2180 if ((mode->dmFields & DM_DISPLAYFLAGS) && (mode->dmDisplayFlags & WINE_DM_UNSUPPORTED))
2181 continue;
2182 if ((devmode->dmFields & DM_BITSPERPEL) && devmode->dmBitsPerPel && devmode->dmBitsPerPel != mode->dmBitsPerPel)
2183 continue;
2184 if ((devmode->dmFields & DM_PELSWIDTH) && devmode->dmPelsWidth != mode->dmPelsWidth)
2185 continue;
2186 if ((devmode->dmFields & DM_PELSHEIGHT) && devmode->dmPelsHeight != mode->dmPelsHeight)
2187 continue;
2188 if ((devmode->dmFields & DM_DISPLAYFREQUENCY) && devmode->dmDisplayFrequency != mode->dmDisplayFrequency
2189 && devmode->dmDisplayFrequency > 1 && mode->dmDisplayFrequency)
2190 continue;
2191 if ((devmode->dmFields & DM_DISPLAYORIENTATION) && devmode->dmDisplayOrientation != mode->dmDisplayOrientation)
2192 continue;
2193 if ((devmode->dmFields & DM_DISPLAYFLAGS) && (mode->dmFields & DM_DISPLAYFLAGS) &&
2194 (devmode->dmDisplayFlags & DM_INTERLACED) != (mode->dmDisplayFlags & DM_INTERLACED))
2195 continue;
2196 if ((devmode->dmFields & DM_DISPLAYFIXEDOUTPUT) && (mode->dmFields & DM_DISPLAYFIXEDOUTPUT) &&
2197 devmode->dmDisplayFixedOutput != mode->dmDisplayFixedOutput)
2198 continue;
2200 return mode;
2203 return NULL;
2206 static BOOL adapter_get_full_mode( const struct adapter *adapter, const DEVMODEW *devmode, DEVMODEW *full_mode )
2208 const DEVMODEW *adapter_mode;
2210 if (devmode)
2212 trace_devmode( devmode );
2214 if (devmode->dmSize < offsetof(DEVMODEW, dmICMMethod)) return FALSE;
2215 if (!is_detached_mode( devmode ) &&
2216 (!(devmode->dmFields & DM_BITSPERPEL) || !devmode->dmBitsPerPel) &&
2217 (!(devmode->dmFields & DM_PELSWIDTH) || !devmode->dmPelsWidth) &&
2218 (!(devmode->dmFields & DM_PELSHEIGHT) || !devmode->dmPelsHeight) &&
2219 (!(devmode->dmFields & DM_DISPLAYFREQUENCY) || !devmode->dmDisplayFrequency))
2220 devmode = NULL;
2223 if (devmode) memcpy( full_mode, devmode, devmode->dmSize );
2224 else
2226 if (!adapter_get_registry_settings( adapter, full_mode )) return FALSE;
2227 TRACE( "Return to original display mode\n" );
2230 if ((full_mode->dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != (DM_PELSWIDTH | DM_PELSHEIGHT))
2232 WARN( "devmode doesn't specify the resolution: %#x\n", (int)full_mode->dmFields );
2233 return FALSE;
2236 if (!is_detached_mode( full_mode ) && (!full_mode->dmPelsWidth || !full_mode->dmPelsHeight || !(full_mode->dmFields & DM_POSITION)))
2238 DEVMODEW current_mode = {.dmSize = sizeof(DEVMODEW)};
2240 if (!adapter_get_current_settings( adapter, &current_mode )) return FALSE;
2241 if (!full_mode->dmPelsWidth) full_mode->dmPelsWidth = current_mode.dmPelsWidth;
2242 if (!full_mode->dmPelsHeight) full_mode->dmPelsHeight = current_mode.dmPelsHeight;
2243 if (!(full_mode->dmFields & DM_POSITION))
2245 full_mode->dmPosition = current_mode.dmPosition;
2246 full_mode->dmFields |= DM_POSITION;
2250 if ((adapter_mode = find_display_mode( adapter->modes, full_mode )) && adapter_mode != full_mode)
2252 POINTL position = full_mode->dmPosition;
2253 *full_mode = *adapter_mode;
2254 full_mode->dmFields |= DM_POSITION;
2255 full_mode->dmPosition = position;
2258 return adapter_mode != NULL;
2261 static DEVMODEW *get_display_settings( const WCHAR *devname, const DEVMODEW *devmode )
2263 DEVMODEW *mode, *displays;
2264 struct adapter *adapter;
2265 BOOL ret;
2267 /* allocate an extra mode for easier iteration */
2268 if (!(displays = calloc( list_count( &adapters ) + 1, sizeof(DEVMODEW) ))) return NULL;
2269 mode = displays;
2271 LIST_FOR_EACH_ENTRY( adapter, &adapters, struct adapter, entry )
2273 mode->dmSize = sizeof(DEVMODEW);
2274 if (devmode && !wcsicmp( devname, adapter->dev.device_name ))
2275 memcpy( &mode->dmFields, &devmode->dmFields, devmode->dmSize - offsetof(DEVMODEW, dmFields) );
2276 else
2278 if (!devname) ret = adapter_get_registry_settings( adapter, mode );
2279 else ret = adapter_get_current_settings( adapter, mode );
2280 if (!ret)
2282 free( displays );
2283 return NULL;
2287 lstrcpyW( mode->dmDeviceName, adapter->dev.device_name );
2288 mode = NEXT_DEVMODEW(mode);
2291 return displays;
2294 static INT offset_length( POINT offset )
2296 return offset.x * offset.x + offset.y * offset.y;
2299 static void set_rect_from_devmode( RECT *rect, const DEVMODEW *mode )
2301 SetRect( rect, mode->dmPosition.x, mode->dmPosition.y, mode->dmPosition.x + mode->dmPelsWidth,
2302 mode->dmPosition.y + mode->dmPelsHeight );
2305 /* Check if a rect overlaps with placed display rects */
2306 static BOOL overlap_placed_displays( const RECT *rect, const DEVMODEW *displays )
2308 const DEVMODEW *mode;
2309 RECT intersect;
2311 for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode))
2313 set_rect_from_devmode( &intersect, mode );
2314 if ((mode->dmFields & DM_POSITION) && intersect_rect( &intersect, &intersect, rect )) return TRUE;
2317 return FALSE;
2320 /* Get the offset with minimum length to place a display next to the placed displays with no spacing and overlaps */
2321 static POINT get_placement_offset( const DEVMODEW *displays, const DEVMODEW *placing )
2323 POINT points[8], left_top, offset, min_offset = {0, 0};
2324 INT point_idx, point_count, vertex_idx;
2325 BOOL has_placed = FALSE, first = TRUE;
2326 RECT desired_rect, rect;
2327 const DEVMODEW *mode;
2328 INT width, height;
2330 set_rect_from_devmode( &desired_rect, placing );
2332 /* If the display to be placed is detached, no offset is needed to place it */
2333 if (IsRectEmpty( &desired_rect )) return min_offset;
2335 /* If there is no placed and attached display, place this display as it is */
2336 for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode))
2338 set_rect_from_devmode( &rect, mode );
2339 if ((mode->dmFields & DM_POSITION) && !IsRectEmpty( &rect ))
2341 has_placed = TRUE;
2342 break;
2346 if (!has_placed) return min_offset;
2348 /* Try to place this display with each of its four vertices at every vertex of the placed
2349 * displays and see which combination has the minimum offset length */
2350 width = desired_rect.right - desired_rect.left;
2351 height = desired_rect.bottom - desired_rect.top;
2353 for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode))
2355 set_rect_from_devmode( &rect, mode );
2356 if (!(mode->dmFields & DM_POSITION) || IsRectEmpty( &rect )) continue;
2358 /* Get four vertices of the placed display rectangle */
2359 points[0].x = rect.left;
2360 points[0].y = rect.top;
2361 points[1].x = rect.left;
2362 points[1].y = rect.bottom;
2363 points[2].x = rect.right;
2364 points[2].y = rect.top;
2365 points[3].x = rect.right;
2366 points[3].y = rect.bottom;
2367 point_count = 4;
2369 /* Intersected points when moving the display to be placed horizontally */
2370 if (desired_rect.bottom >= rect.top && desired_rect.top <= rect.bottom)
2372 points[point_count].x = rect.left;
2373 points[point_count++].y = desired_rect.top;
2374 points[point_count].x = rect.right;
2375 points[point_count++].y = desired_rect.top;
2377 /* Intersected points when moving the display to be placed vertically */
2378 if (desired_rect.left <= rect.right && desired_rect.right >= rect.left)
2380 points[point_count].x = desired_rect.left;
2381 points[point_count++].y = rect.top;
2382 points[point_count].x = desired_rect.left;
2383 points[point_count++].y = rect.bottom;
2386 /* Try moving each vertex of the display rectangle to each points */
2387 for (point_idx = 0; point_idx < point_count; ++point_idx)
2389 for (vertex_idx = 0; vertex_idx < 4; ++vertex_idx)
2391 switch (vertex_idx)
2393 /* Move the bottom right vertex to the point */
2394 case 0:
2395 left_top.x = points[point_idx].x - width;
2396 left_top.y = points[point_idx].y - height;
2397 break;
2398 /* Move the bottom left vertex to the point */
2399 case 1:
2400 left_top.x = points[point_idx].x;
2401 left_top.y = points[point_idx].y - height;
2402 break;
2403 /* Move the top right vertex to the point */
2404 case 2:
2405 left_top.x = points[point_idx].x - width;
2406 left_top.y = points[point_idx].y;
2407 break;
2408 /* Move the top left vertex to the point */
2409 case 3:
2410 left_top.x = points[point_idx].x;
2411 left_top.y = points[point_idx].y;
2412 break;
2415 offset.x = left_top.x - desired_rect.left;
2416 offset.y = left_top.y - desired_rect.top;
2417 rect = desired_rect;
2418 OffsetRect( &rect, offset.x, offset.y );
2419 if (!overlap_placed_displays( &rect, displays ))
2421 if (first)
2423 min_offset = offset;
2424 first = FALSE;
2425 continue;
2428 if (offset_length( offset ) < offset_length( min_offset )) min_offset = offset;
2434 return min_offset;
2437 static void place_all_displays( DEVMODEW *displays )
2439 POINT min_offset, offset;
2440 DEVMODEW *mode, *placing;
2442 for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode))
2443 mode->dmFields &= ~DM_POSITION;
2445 /* Place all displays with no extra space between them and no overlapping */
2446 while (1)
2448 /* Place the unplaced display with the minimum offset length first */
2449 placing = NULL;
2450 for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode))
2452 if (mode->dmFields & DM_POSITION) continue;
2454 offset = get_placement_offset( displays, mode );
2455 if (!placing || offset_length( offset ) < offset_length( min_offset ))
2457 min_offset = offset;
2458 placing = mode;
2462 /* If all displays are placed */
2463 if (!placing) break;
2465 placing->dmPosition.x += min_offset.x;
2466 placing->dmPosition.y += min_offset.y;
2467 placing->dmFields |= DM_POSITION;
2471 static BOOL all_detached_settings( const DEVMODEW *displays )
2473 const DEVMODEW *mode;
2475 for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode))
2476 if (!is_detached_mode( mode )) return FALSE;
2478 return TRUE;
2481 static LONG apply_display_settings( const WCHAR *devname, const DEVMODEW *devmode,
2482 HWND hwnd, DWORD flags, void *lparam )
2484 WCHAR primary_name[CCHDEVICENAME];
2485 struct display_device *primary;
2486 DEVMODEW *mode, *displays;
2487 struct adapter *adapter;
2488 LONG ret;
2490 if (!lock_display_devices()) return DISP_CHANGE_FAILED;
2491 if (!(displays = get_display_settings( devname, devmode )))
2493 unlock_display_devices();
2494 return DISP_CHANGE_FAILED;
2497 if (all_detached_settings( displays ))
2499 unlock_display_devices();
2500 WARN( "Detaching all modes is not permitted.\n" );
2501 free( displays );
2502 return DISP_CHANGE_SUCCESSFUL;
2505 place_all_displays( displays );
2507 if (!(primary = find_adapter_device_by_id( 0 ))) primary_name[0] = 0;
2508 else wcscpy( primary_name, primary->device_name );
2510 if ((ret = user_driver->pChangeDisplaySettings( displays, primary_name, hwnd, flags, lparam )) == E_NOTIMPL)
2512 /* default implementation: write current display settings to the registry. */
2513 mode = displays;
2514 LIST_FOR_EACH_ENTRY( adapter, &adapters, struct adapter, entry )
2516 if (!adapter_set_current_settings( adapter, mode ))
2517 WARN( "Failed to write adapter %s current mode.\n", debugstr_w(adapter->dev.device_name) );
2518 mode = NEXT_DEVMODEW(mode);
2520 ret = DISP_CHANGE_SUCCESSFUL;
2522 unlock_display_devices();
2524 free( displays );
2525 if (ret) return ret;
2527 if (!update_display_cache( TRUE ))
2528 WARN( "Failed to update display cache after mode change.\n" );
2530 if ((adapter = find_adapter( NULL )))
2532 DEVMODEW current_mode = {.dmSize = sizeof(DEVMODEW)};
2534 if (!adapter_get_current_settings( adapter, &current_mode )) WARN( "Failed to get primary adapter current display settings.\n" );
2535 adapter_release( adapter );
2537 send_notify_message( NtUserGetDesktopWindow(), WM_DISPLAYCHANGE, current_mode.dmBitsPerPel,
2538 MAKELPARAM( current_mode.dmPelsWidth, current_mode.dmPelsHeight ), FALSE );
2539 send_message_timeout( HWND_BROADCAST, WM_DISPLAYCHANGE, current_mode.dmBitsPerPel,
2540 MAKELPARAM( current_mode.dmPelsWidth, current_mode.dmPelsHeight ),
2541 SMTO_ABORTIFHUNG, 2000, FALSE );
2544 return ret;
2547 /***********************************************************************
2548 * NtUserChangeDisplaySettings (win32u.@)
2550 LONG WINAPI NtUserChangeDisplaySettings( UNICODE_STRING *devname, DEVMODEW *devmode, HWND hwnd,
2551 DWORD flags, void *lparam )
2553 DEVMODEW full_mode = {.dmSize = sizeof(DEVMODEW)};
2554 int ret = DISP_CHANGE_SUCCESSFUL;
2555 struct adapter *adapter;
2557 TRACE( "%s %p %p %#x %p\n", debugstr_us(devname), devmode, hwnd, (int)flags, lparam );
2558 TRACE( "flags=%s\n", _CDS_flags(flags) );
2560 if ((!devname || !devname->Length) && !devmode) return apply_display_settings( NULL, NULL, hwnd, flags, lparam );
2562 if (!(adapter = find_adapter( devname ))) return DISP_CHANGE_BADPARAM;
2564 if (!adapter_get_full_mode( adapter, devmode, &full_mode )) ret = DISP_CHANGE_BADMODE;
2565 else if ((flags & CDS_UPDATEREGISTRY) && !adapter_set_registry_settings( adapter, &full_mode )) ret = DISP_CHANGE_NOTUPDATED;
2566 else if (flags & (CDS_TEST | CDS_NORESET)) ret = DISP_CHANGE_SUCCESSFUL;
2567 else ret = apply_display_settings( adapter->dev.device_name, &full_mode, hwnd, flags, lparam );
2568 adapter_release( adapter );
2570 if (ret) ERR( "Changing %s display settings returned %d.\n", debugstr_us(devname), ret );
2571 return ret;
2574 static BOOL adapter_enum_display_settings( const struct adapter *adapter, UINT index, DEVMODEW *devmode, UINT flags )
2576 DEVMODEW current_mode = {.dmSize = sizeof(DEVMODEW)};
2577 const DEVMODEW *adapter_mode;
2579 if (!(flags & EDS_ROTATEDMODE) && !adapter_get_current_settings( adapter, &current_mode ))
2581 WARN( "Failed to query current display mode for EDS_ROTATEDMODE flag.\n" );
2582 return FALSE;
2585 for (adapter_mode = adapter->modes; adapter_mode->dmSize; adapter_mode = NEXT_DEVMODEW(adapter_mode))
2587 if (!(flags & EDS_ROTATEDMODE) && (adapter_mode->dmFields & DM_DISPLAYORIENTATION) &&
2588 adapter_mode->dmDisplayOrientation != current_mode.dmDisplayOrientation)
2589 continue;
2590 if (!(flags & EDS_RAWMODE) && (adapter_mode->dmFields & DM_DISPLAYFLAGS) &&
2591 (adapter_mode->dmDisplayFlags & WINE_DM_UNSUPPORTED))
2592 continue;
2593 if (!index--)
2595 memcpy( &devmode->dmFields, &adapter_mode->dmFields, devmode->dmSize - FIELD_OFFSET(DEVMODEW, dmFields) );
2596 devmode->dmDisplayFlags &= ~WINE_DM_UNSUPPORTED;
2597 return TRUE;
2601 WARN( "device %s, index %#x, flags %#x display mode not found.\n",
2602 debugstr_w( adapter->dev.device_name ), index, flags );
2603 RtlSetLastWin32Error( ERROR_NO_MORE_FILES );
2604 return FALSE;
2607 /***********************************************************************
2608 * NtUserEnumDisplaySettings (win32u.@)
2610 BOOL WINAPI NtUserEnumDisplaySettings( UNICODE_STRING *device, DWORD index, DEVMODEW *devmode, DWORD flags )
2612 static const WCHAR wine_display_driverW[] = {'W','i','n','e',' ','D','i','s','p','l','a','y',' ','D','r','i','v','e','r',0};
2613 struct adapter *adapter;
2614 BOOL ret;
2616 TRACE( "device %s, index %#x, devmode %p, flags %#x\n",
2617 debugstr_us(device), (int)index, devmode, (int)flags );
2619 if (!(adapter = find_adapter( device ))) return FALSE;
2621 lstrcpynW( devmode->dmDeviceName, wine_display_driverW, ARRAY_SIZE(devmode->dmDeviceName) );
2622 devmode->dmSpecVersion = DM_SPECVERSION;
2623 devmode->dmDriverVersion = DM_SPECVERSION;
2624 devmode->dmSize = offsetof(DEVMODEW, dmICMMethod);
2625 devmode->dmDriverExtra = 0;
2627 if (index == ENUM_REGISTRY_SETTINGS) ret = adapter_get_registry_settings( adapter, devmode );
2628 else if (index == ENUM_CURRENT_SETTINGS) ret = adapter_get_current_settings( adapter, devmode );
2629 else ret = adapter_enum_display_settings( adapter, index, devmode, flags );
2630 adapter_release( adapter );
2632 if (!ret) WARN( "Failed to query %s display settings.\n", debugstr_us(device) );
2633 else TRACE( "position %dx%d, resolution %ux%u, frequency %u, depth %u, orientation %#x.\n",
2634 (int)devmode->dmPosition.x, (int)devmode->dmPosition.y, (int)devmode->dmPelsWidth,
2635 (int)devmode->dmPelsHeight, (int)devmode->dmDisplayFrequency,
2636 (int)devmode->dmBitsPerPel, (int)devmode->dmDisplayOrientation );
2637 return ret;
2640 struct monitor_enum_info
2642 HANDLE handle;
2643 RECT rect;
2646 static unsigned int active_monitor_count(void)
2648 struct monitor *monitor;
2649 unsigned int count = 0;
2651 LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry)
2653 if ((monitor->dev.state_flags & DISPLAY_DEVICE_ACTIVE)) count++;
2655 return count;
2658 /***********************************************************************
2659 * NtUserEnumDisplayMonitors (win32u.@)
2661 BOOL WINAPI NtUserEnumDisplayMonitors( HDC hdc, RECT *rect, MONITORENUMPROC proc, LPARAM lparam )
2663 struct monitor_enum_info enum_buf[8], *enum_info = enum_buf;
2664 struct enum_display_monitor_params params;
2665 struct monitor *monitor;
2666 unsigned int count = 0, i;
2667 POINT origin;
2668 RECT limit;
2669 BOOL ret = TRUE;
2671 if (hdc)
2673 DC *dc;
2674 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
2675 origin.x = dc->attr->vis_rect.left;
2676 origin.y = dc->attr->vis_rect.top;
2677 release_dc_ptr( dc );
2678 if (NtGdiGetAppClipBox( hdc, &limit ) == ERROR) return FALSE;
2680 else
2682 origin.x = origin.y = 0;
2683 limit.left = limit.top = INT_MIN;
2684 limit.right = limit.bottom = INT_MAX;
2686 if (rect && !intersect_rect( &limit, &limit, rect )) return TRUE;
2688 if (!lock_display_devices()) return FALSE;
2690 count = list_count( &monitors );
2691 if (!count || (count > ARRAYSIZE(enum_buf) &&
2692 !(enum_info = malloc( count * sizeof(*enum_info) ))))
2694 unlock_display_devices();
2695 return FALSE;
2698 count = 0;
2699 LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry)
2701 RECT monrect;
2703 if (!(monitor->dev.state_flags & DISPLAY_DEVICE_ACTIVE)) continue;
2705 monrect = map_dpi_rect( monitor->rc_monitor, get_monitor_dpi( monitor->handle ),
2706 get_thread_dpi() );
2707 OffsetRect( &monrect, -origin.x, -origin.y );
2708 if (!intersect_rect( &monrect, &monrect, &limit )) continue;
2709 if (monitor->is_clone) continue;
2711 enum_info[count].handle = monitor->handle;
2712 enum_info[count].rect = monrect;
2713 count++;
2716 unlock_display_devices();
2718 params.proc = proc;
2719 params.hdc = hdc;
2720 params.lparam = lparam;
2721 for (i = 0; i < count; i++)
2723 void *ret_ptr;
2724 ULONG ret_len;
2725 params.monitor = enum_info[i].handle;
2726 params.rect = enum_info[i].rect;
2727 if (!KeUserModeCallback( NtUserCallEnumDisplayMonitor, &params, sizeof(params),
2728 &ret_ptr, &ret_len ))
2730 ret = FALSE;
2731 break;
2734 if (enum_info != enum_buf) free( enum_info );
2735 return ret;
2738 BOOL get_monitor_info( HMONITOR handle, MONITORINFO *info )
2740 struct monitor *monitor;
2741 UINT dpi_from, dpi_to;
2743 if (info->cbSize != sizeof(MONITORINFOEXW) && info->cbSize != sizeof(MONITORINFO)) return FALSE;
2745 if (!lock_display_devices()) return FALSE;
2747 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
2749 if (monitor->handle != handle) continue;
2750 if (!(monitor->dev.state_flags & DISPLAY_DEVICE_ACTIVE)) break;
2752 /* FIXME: map dpi */
2753 info->rcMonitor = monitor->rc_monitor;
2754 info->rcWork = monitor->rc_work;
2755 info->dwFlags = monitor->flags;
2756 if (info->cbSize >= sizeof(MONITORINFOEXW))
2758 if (monitor->adapter)
2759 lstrcpyW( ((MONITORINFOEXW *)info)->szDevice, monitor->adapter->dev.device_name );
2760 else
2761 asciiz_to_unicode( ((MONITORINFOEXW *)info)->szDevice, "WinDisc" );
2763 unlock_display_devices();
2765 if ((dpi_to = get_thread_dpi()))
2767 dpi_from = get_monitor_dpi( handle );
2768 info->rcMonitor = map_dpi_rect( info->rcMonitor, dpi_from, dpi_to );
2769 info->rcWork = map_dpi_rect( info->rcWork, dpi_from, dpi_to );
2771 TRACE( "flags %04x, monitor %s, work %s\n", (int)info->dwFlags,
2772 wine_dbgstr_rect(&info->rcMonitor), wine_dbgstr_rect(&info->rcWork));
2773 return TRUE;
2776 unlock_display_devices();
2777 WARN( "invalid handle %p\n", handle );
2778 RtlSetLastWin32Error( ERROR_INVALID_MONITOR_HANDLE );
2779 return FALSE;
2782 HMONITOR monitor_from_rect( const RECT *rect, UINT flags, UINT dpi )
2784 HMONITOR primary = 0, nearest = 0, ret = 0;
2785 UINT max_area = 0, min_distance = ~0u;
2786 struct monitor *monitor;
2787 RECT r;
2789 r = map_dpi_rect( *rect, dpi, system_dpi );
2790 if (IsRectEmpty( &r ))
2792 r.right = r.left + 1;
2793 r.bottom = r.top + 1;
2796 if (!lock_display_devices()) return 0;
2798 LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry)
2800 RECT intersect;
2801 RECT monitor_rect = map_dpi_rect( monitor->rc_monitor, get_monitor_dpi( monitor->handle ),
2802 system_dpi );
2804 if (intersect_rect( &intersect, &monitor_rect, &r ))
2806 /* check for larger intersecting area */
2807 UINT area = (intersect.right - intersect.left) * (intersect.bottom - intersect.top);
2808 if (area > max_area)
2810 max_area = area;
2811 ret = monitor->handle;
2814 else if (!max_area) /* if not intersecting, check for min distance */
2816 UINT distance;
2817 UINT x, y;
2819 if (r.right <= monitor_rect.left) x = monitor_rect.left - r.right;
2820 else if (monitor_rect.right <= r.left) x = r.left - monitor_rect.right;
2821 else x = 0;
2822 if (r.bottom <= monitor_rect.top) y = monitor_rect.top - r.bottom;
2823 else if (monitor_rect.bottom <= r.top) y = r.top - monitor_rect.bottom;
2824 else y = 0;
2825 distance = x * x + y * y;
2826 if (distance < min_distance)
2828 min_distance = distance;
2829 nearest = monitor->handle;
2833 if (monitor->flags & MONITORINFOF_PRIMARY) primary = monitor->handle;
2836 unlock_display_devices();
2838 if (!ret)
2840 if (flags & MONITOR_DEFAULTTOPRIMARY) ret = primary;
2841 else if (flags & MONITOR_DEFAULTTONEAREST) ret = nearest;
2844 TRACE( "%s flags %x returning %p\n", wine_dbgstr_rect(rect), flags, ret );
2845 return ret;
2848 HMONITOR monitor_from_point( POINT pt, UINT flags, UINT dpi )
2850 RECT rect;
2851 SetRect( &rect, pt.x, pt.y, pt.x + 1, pt.y + 1 );
2852 return monitor_from_rect( &rect, flags, dpi );
2855 /* see MonitorFromWindow */
2856 HMONITOR monitor_from_window( HWND hwnd, UINT flags, UINT dpi )
2858 RECT rect;
2859 WINDOWPLACEMENT wp;
2861 TRACE( "(%p, 0x%08x)\n", hwnd, flags );
2863 wp.length = sizeof(wp);
2864 if (is_iconic( hwnd ) && NtUserGetWindowPlacement( hwnd, &wp ))
2865 return monitor_from_rect( &wp.rcNormalPosition, flags, dpi );
2867 if (get_window_rect( hwnd, &rect, dpi ))
2868 return monitor_from_rect( &rect, flags, dpi );
2870 if (!(flags & (MONITOR_DEFAULTTOPRIMARY|MONITOR_DEFAULTTONEAREST))) return 0;
2871 /* retrieve the primary */
2872 SetRect( &rect, 0, 0, 1, 1 );
2873 return monitor_from_rect( &rect, flags, dpi );
2876 /***********************************************************************
2877 * NtUserGetSystemDpiForProcess (win32u.@)
2879 ULONG WINAPI NtUserGetSystemDpiForProcess( HANDLE process )
2881 if (process && process != GetCurrentProcess())
2883 FIXME( "not supported on other process %p\n", process );
2884 return 0;
2887 return system_dpi;
2890 /***********************************************************************
2891 * NtUserGetDpiForMonitor (win32u.@)
2893 BOOL WINAPI NtUserGetDpiForMonitor( HMONITOR monitor, UINT type, UINT *x, UINT *y )
2895 if (type > 2)
2897 RtlSetLastWin32Error( ERROR_BAD_ARGUMENTS );
2898 return FALSE;
2900 if (!x || !y)
2902 RtlSetLastWin32Error( ERROR_INVALID_ADDRESS );
2903 return FALSE;
2905 switch (get_thread_dpi_awareness())
2907 case DPI_AWARENESS_UNAWARE: *x = *y = USER_DEFAULT_SCREEN_DPI; break;
2908 case DPI_AWARENESS_SYSTEM_AWARE: *x = *y = system_dpi; break;
2909 default: *x = *y = get_monitor_dpi( monitor ); break;
2911 return TRUE;
2914 /**********************************************************************
2915 * LogicalToPhysicalPointForPerMonitorDPI (win32u.@)
2917 BOOL WINAPI NtUserLogicalToPerMonitorDPIPhysicalPoint( HWND hwnd, POINT *pt )
2919 RECT rect;
2921 if (!get_window_rect( hwnd, &rect, get_thread_dpi() )) return FALSE;
2922 if (pt->x < rect.left || pt->y < rect.top || pt->x > rect.right || pt->y > rect.bottom) return FALSE;
2923 *pt = point_win_to_phys_dpi( hwnd, *pt );
2924 return TRUE;
2927 /**********************************************************************
2928 * NtUserPerMonitorDPIPhysicalToLogicalPoint (win32u.@)
2930 BOOL WINAPI NtUserPerMonitorDPIPhysicalToLogicalPoint( HWND hwnd, POINT *pt )
2932 RECT rect;
2933 BOOL ret = FALSE;
2935 if (get_window_rect( hwnd, &rect, 0 ) &&
2936 pt->x >= rect.left && pt->y >= rect.top && pt->x <= rect.right && pt->y <= rect.bottom)
2938 *pt = point_phys_to_win_dpi( hwnd, *pt );
2939 ret = TRUE;
2941 return ret;
2944 /* retrieve the cached base keys for a given entry */
2945 static BOOL get_base_keys( enum parameter_key index, HKEY *base_key, HKEY *volatile_key )
2947 static HKEY base_keys[NB_PARAM_KEYS];
2948 static HKEY volatile_keys[NB_PARAM_KEYS];
2949 WCHAR bufferW[128];
2950 HKEY key;
2952 if (!base_keys[index] && base_key)
2954 if (!(key = reg_create_key( hkcu_key, bufferW,
2955 asciiz_to_unicode( bufferW, parameter_key_names[index] ) - sizeof(WCHAR),
2956 0, NULL )))
2957 return FALSE;
2958 if (InterlockedCompareExchangePointer( (void **)&base_keys[index], key, 0 ))
2959 NtClose( key );
2961 if (!volatile_keys[index] && volatile_key)
2963 if (!(key = reg_create_key( volatile_base_key, bufferW,
2964 asciiz_to_unicode( bufferW, parameter_key_names[index] ) - sizeof(WCHAR),
2965 REG_OPTION_VOLATILE, NULL )))
2966 return FALSE;
2967 if (InterlockedCompareExchangePointer( (void **)&volatile_keys[index], key, 0 ))
2968 NtClose( key );
2970 if (base_key) *base_key = base_keys[index];
2971 if (volatile_key) *volatile_key = volatile_keys[index];
2972 return TRUE;
2975 /* load a value to a registry entry */
2976 static DWORD load_entry( struct sysparam_entry *entry, void *data, DWORD size )
2978 char buffer[4096];
2979 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
2980 DWORD count;
2981 HKEY base_key, volatile_key;
2983 if (!get_base_keys( entry->base_key, &base_key, &volatile_key )) return FALSE;
2985 if (!(count = query_reg_ascii_value( volatile_key, entry->regval, value, sizeof(buffer) )))
2986 count = query_reg_ascii_value( base_key, entry->regval, value, sizeof(buffer) );
2987 if (count > size)
2989 count = size;
2990 /* make sure strings are null-terminated */
2991 if (value->Type == REG_SZ) ((WCHAR *)value->Data)[count / sizeof(WCHAR) - 1] = 0;
2993 if (count) memcpy( data, value->Data, count );
2994 entry->loaded = TRUE;
2995 return count;
2998 /* save a value to a registry entry */
2999 static BOOL save_entry( const struct sysparam_entry *entry, const void *data, DWORD size,
3000 DWORD type, UINT flags )
3002 HKEY base_key, volatile_key;
3003 WCHAR nameW[64];
3005 asciiz_to_unicode( nameW, entry->regval );
3006 if (flags & SPIF_UPDATEINIFILE)
3008 if (!get_base_keys( entry->base_key, &base_key, &volatile_key )) return FALSE;
3009 if (!set_reg_value( base_key, nameW, type, data, size )) return FALSE;
3010 reg_delete_value( volatile_key, nameW );
3012 if (entry->mirror && get_base_keys( entry->mirror_key, &base_key, NULL ))
3014 asciiz_to_unicode( nameW, entry->mirror );
3015 set_reg_value( base_key, nameW, type, data, size );
3018 else
3020 if (!get_base_keys( entry->base_key, NULL, &volatile_key )) return FALSE;
3021 if (!set_reg_value( volatile_key, nameW, type, data, size )) return FALSE;
3023 return TRUE;
3026 /* save a string value to a registry entry */
3027 static BOOL save_entry_string( const struct sysparam_entry *entry, const WCHAR *str, UINT flags )
3029 return save_entry( entry, str, (lstrlenW(str) + 1) * sizeof(WCHAR), REG_SZ, flags );
3032 /* initialize an entry in the registry if missing */
3033 static BOOL init_entry( struct sysparam_entry *entry, const void *data, DWORD size, DWORD type )
3035 KEY_VALUE_PARTIAL_INFORMATION value;
3036 UNICODE_STRING name;
3037 WCHAR nameW[64];
3038 HKEY base_key;
3039 DWORD count;
3040 NTSTATUS status;
3042 if (!get_base_keys( entry->base_key, &base_key, NULL )) return FALSE;
3044 name.Buffer = nameW;
3045 name.MaximumLength = asciiz_to_unicode( nameW, entry->regval );
3046 name.Length = name.MaximumLength - sizeof(WCHAR);
3047 status = NtQueryValueKey( base_key, &name, KeyValuePartialInformation,
3048 &value, sizeof(value), &count );
3049 if (!status || status == STATUS_BUFFER_OVERFLOW) return TRUE;
3051 if (!set_reg_value( base_key, nameW, type, data, size )) return FALSE;
3052 if (entry->mirror && get_base_keys( entry->mirror_key, &base_key, NULL ))
3054 asciiz_to_unicode( nameW, entry->mirror );
3055 set_reg_value( base_key, nameW, type, data, size );
3057 entry->loaded = TRUE;
3058 return TRUE;
3061 /* initialize a string value in the registry if missing */
3062 static BOOL init_entry_string( struct sysparam_entry *entry, const WCHAR *str )
3064 return init_entry( entry, str, (lstrlenW(str) + 1) * sizeof(WCHAR), REG_SZ );
3067 /* set an int parameter in the registry */
3068 static BOOL set_int_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
3070 WCHAR bufW[32];
3071 char buf[32];
3073 sprintf( buf, "%d", int_param );
3074 asciiz_to_unicode( bufW, buf );
3075 if (!save_entry_string( &entry->hdr, bufW, flags )) return FALSE;
3076 entry->uint.val = int_param;
3077 entry->hdr.loaded = TRUE;
3078 return TRUE;
3081 /* initialize an int parameter */
3082 static BOOL init_int_entry( union sysparam_all_entry *entry )
3084 WCHAR bufW[32];
3085 char buf[32];
3087 sprintf( buf, "%d", entry->uint.val );
3088 asciiz_to_unicode( bufW, buf );
3089 return init_entry_string( &entry->hdr, bufW );
3092 /* load a uint parameter from the registry */
3093 static BOOL get_uint_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
3095 if (!ptr_param) return FALSE;
3097 if (!entry->hdr.loaded)
3099 WCHAR buf[32];
3100 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->uint.val = wcstol( buf, NULL, 10 );
3102 *(UINT *)ptr_param = entry->uint.val;
3103 return TRUE;
3106 /* set a uint parameter in the registry */
3107 static BOOL set_uint_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
3109 WCHAR bufW[32];
3110 char buf[32];
3112 sprintf( buf, "%u", int_param );
3113 asciiz_to_unicode( bufW, buf );
3114 if (!save_entry_string( &entry->hdr, bufW, flags )) return FALSE;
3115 entry->uint.val = int_param;
3116 entry->hdr.loaded = TRUE;
3117 return TRUE;
3120 /* initialize a uint parameter */
3121 static BOOL init_uint_entry( union sysparam_all_entry *entry )
3123 WCHAR bufW[32];
3124 char buf[32];
3126 sprintf( buf, "%u", entry->uint.val );
3127 asciiz_to_unicode( bufW, buf );
3128 return init_entry_string( &entry->hdr, bufW );
3131 /* load a twips parameter from the registry */
3132 static BOOL get_twips_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
3134 int val;
3136 if (!ptr_param) return FALSE;
3138 if (!entry->hdr.loaded)
3140 WCHAR buf[32];
3141 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->uint.val = wcstol( buf, NULL, 10 );
3144 /* Dimensions are quoted as being "twips" values if negative and pixels if positive.
3145 * One inch is 1440 twips.
3146 * See for example
3147 * Technical Reference to the Windows 2000 Registry ->
3148 * HKEY_CURRENT_USER -> Control Panel -> Desktop -> WindowMetrics
3150 val = entry->uint.val;
3151 if (val < 0)
3152 val = muldiv( -val, dpi, 1440 );
3153 else
3154 val = map_to_dpi( val, dpi );
3156 *(int *)ptr_param = val;
3157 return TRUE;
3160 /* set a twips parameter in the registry */
3161 static BOOL set_twips_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
3163 int val = int_param;
3164 if (val > 0) val = map_from_system_dpi( val );
3165 return set_int_entry( entry, val, ptr_param, flags );
3168 /* load a bool parameter from the registry */
3169 static BOOL get_bool_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
3171 if (!ptr_param) return FALSE;
3173 if (!entry->hdr.loaded)
3175 WCHAR buf[32];
3176 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->bool.val = wcstol( buf, NULL, 10 ) != 0;
3178 *(UINT *)ptr_param = entry->bool.val;
3179 return TRUE;
3182 /* set a bool parameter in the registry */
3183 static BOOL set_bool_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
3185 WCHAR buf[] = { int_param ? '1' : '0', 0 };
3187 if (!save_entry_string( &entry->hdr, buf, flags )) return FALSE;
3188 entry->bool.val = int_param != 0;
3189 entry->hdr.loaded = TRUE;
3190 return TRUE;
3193 /* initialize a bool parameter */
3194 static BOOL init_bool_entry( union sysparam_all_entry *entry )
3196 WCHAR buf[] = { entry->bool.val ? '1' : '0', 0 };
3198 return init_entry_string( &entry->hdr, buf );
3201 /* load a bool parameter using Yes/No strings from the registry */
3202 static BOOL get_yesno_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
3204 if (!ptr_param) return FALSE;
3206 if (!entry->hdr.loaded)
3208 WCHAR buf[32];
3209 if (load_entry( &entry->hdr, buf, sizeof(buf) )) entry->bool.val = !wcsicmp( yesW, buf );
3211 *(UINT *)ptr_param = entry->bool.val;
3212 return TRUE;
3215 /* set a bool parameter using Yes/No strings from the registry */
3216 static BOOL set_yesno_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
3218 const WCHAR *str = int_param ? yesW : noW;
3220 if (!save_entry_string( &entry->hdr, str, flags )) return FALSE;
3221 entry->bool.val = int_param != 0;
3222 entry->hdr.loaded = TRUE;
3223 return TRUE;
3226 /* initialize a bool parameter using Yes/No strings */
3227 static BOOL init_yesno_entry( union sysparam_all_entry *entry )
3229 return init_entry_string( &entry->hdr, entry->bool.val ? yesW : noW );
3232 /* load a dword (binary) parameter from the registry */
3233 static BOOL get_dword_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
3235 if (!ptr_param) return FALSE;
3237 if (!entry->hdr.loaded)
3239 DWORD val;
3240 if (load_entry( &entry->hdr, &val, sizeof(val) ) == sizeof(DWORD)) entry->dword.val = val;
3242 *(DWORD *)ptr_param = entry->dword.val;
3243 return TRUE;
3246 /* set a dword (binary) parameter in the registry */
3247 static BOOL set_dword_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
3249 DWORD val = PtrToUlong( ptr_param );
3251 if (!save_entry( &entry->hdr, &val, sizeof(val), REG_DWORD, flags )) return FALSE;
3252 entry->dword.val = val;
3253 entry->hdr.loaded = TRUE;
3254 return TRUE;
3257 /* initialize a dword parameter */
3258 static BOOL init_dword_entry( union sysparam_all_entry *entry )
3260 return init_entry( &entry->hdr, &entry->dword.val, sizeof(entry->dword.val), REG_DWORD );
3263 /* load an RGB parameter from the registry */
3264 static BOOL get_rgb_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
3266 if (!ptr_param) return FALSE;
3268 if (!entry->hdr.loaded)
3270 WCHAR buf[32];
3272 if (load_entry( &entry->hdr, buf, sizeof(buf) ))
3274 DWORD r, g, b;
3275 WCHAR *end, *str = buf;
3277 r = wcstoul( str, &end, 10 );
3278 if (end == str || !*end) goto done;
3279 str = end + 1;
3280 g = wcstoul( str, &end, 10 );
3281 if (end == str || !*end) goto done;
3282 str = end + 1;
3283 b = wcstoul( str, &end, 10 );
3284 if (end == str) goto done;
3285 if (r > 255 || g > 255 || b > 255) goto done;
3286 entry->rgb.val = RGB( r, g, b );
3289 done:
3290 *(COLORREF *)ptr_param = entry->rgb.val;
3291 return TRUE;
3294 /* set an RGB parameter in the registry */
3295 static BOOL set_rgb_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
3297 WCHAR bufW[32];
3298 char buf[32];
3299 HBRUSH brush;
3300 HPEN pen;
3302 sprintf( buf, "%u %u %u", GetRValue(int_param), GetGValue(int_param), GetBValue(int_param) );
3303 asciiz_to_unicode( bufW, buf );
3304 if (!save_entry_string( &entry->hdr, bufW, flags )) return FALSE;
3305 entry->rgb.val = int_param;
3306 entry->hdr.loaded = TRUE;
3307 if ((brush = InterlockedExchangePointer( (void **)&entry->rgb.brush, 0 )))
3309 make_gdi_object_system( brush, FALSE );
3310 NtGdiDeleteObjectApp( brush );
3312 if ((pen = InterlockedExchangePointer( (void **)&entry->rgb.pen, 0 )))
3314 make_gdi_object_system( pen, FALSE );
3315 NtGdiDeleteObjectApp( pen );
3317 return TRUE;
3320 /* initialize an RGB parameter */
3321 static BOOL init_rgb_entry( union sysparam_all_entry *entry )
3323 WCHAR bufW[32];
3324 char buf[32];
3326 sprintf( buf, "%u %u %u", GetRValue(entry->rgb.val), GetGValue(entry->rgb.val),
3327 GetBValue(entry->rgb.val) );
3328 asciiz_to_unicode( bufW, buf );
3329 return init_entry_string( &entry->hdr, bufW );
3332 /* get a path parameter in the registry */
3333 static BOOL get_path_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
3335 if (!ptr_param) return FALSE;
3337 if (!entry->hdr.loaded)
3339 WCHAR buffer[MAX_PATH];
3341 if (load_entry( &entry->hdr, buffer, sizeof(buffer) ))
3342 lstrcpynW( entry->path.path, buffer, MAX_PATH );
3344 lstrcpynW( ptr_param, entry->path.path, int_param );
3345 return TRUE;
3348 /* set a path parameter in the registry */
3349 static BOOL set_path_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
3351 WCHAR buffer[MAX_PATH];
3352 BOOL ret;
3354 lstrcpynW( buffer, ptr_param, MAX_PATH );
3355 ret = save_entry_string( &entry->hdr, buffer, flags );
3356 if (ret)
3358 lstrcpyW( entry->path.path, buffer );
3359 entry->hdr.loaded = TRUE;
3361 return ret;
3364 /* initialize a path parameter */
3365 static BOOL init_path_entry( union sysparam_all_entry *entry )
3367 return init_entry_string( &entry->hdr, entry->path.path );
3370 /* get a binary parameter in the registry */
3371 static BOOL get_binary_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
3373 if (!ptr_param) return FALSE;
3375 if (!entry->hdr.loaded)
3377 void *buffer = malloc( entry->bin.size );
3378 DWORD len = load_entry( &entry->hdr, buffer, entry->bin.size );
3380 if (len)
3382 memcpy( entry->bin.ptr, buffer, entry->bin.size );
3383 memset( (char *)entry->bin.ptr + len, 0, entry->bin.size - len );
3385 free( buffer );
3387 memcpy( ptr_param, entry->bin.ptr, min( int_param, entry->bin.size ) );
3388 return TRUE;
3391 /* set a binary parameter in the registry */
3392 static BOOL set_binary_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
3394 BOOL ret;
3395 void *buffer = malloc( entry->bin.size );
3397 memcpy( buffer, entry->bin.ptr, entry->bin.size );
3398 memcpy( buffer, ptr_param, min( int_param, entry->bin.size ));
3399 ret = save_entry( &entry->hdr, buffer, entry->bin.size, REG_BINARY, flags );
3400 if (ret)
3402 memcpy( entry->bin.ptr, buffer, entry->bin.size );
3403 entry->hdr.loaded = TRUE;
3405 free( buffer );
3406 return ret;
3409 /* initialize a binary parameter */
3410 static BOOL init_binary_entry( union sysparam_all_entry *entry )
3412 return init_entry( &entry->hdr, entry->bin.ptr, entry->bin.size, REG_BINARY );
3415 static void logfont16to32( const LOGFONT16 *font16, LPLOGFONTW font32 )
3417 font32->lfHeight = font16->lfHeight;
3418 font32->lfWidth = font16->lfWidth;
3419 font32->lfEscapement = font16->lfEscapement;
3420 font32->lfOrientation = font16->lfOrientation;
3421 font32->lfWeight = font16->lfWeight;
3422 font32->lfItalic = font16->lfItalic;
3423 font32->lfUnderline = font16->lfUnderline;
3424 font32->lfStrikeOut = font16->lfStrikeOut;
3425 font32->lfCharSet = font16->lfCharSet;
3426 font32->lfOutPrecision = font16->lfOutPrecision;
3427 font32->lfClipPrecision = font16->lfClipPrecision;
3428 font32->lfQuality = font16->lfQuality;
3429 font32->lfPitchAndFamily = font16->lfPitchAndFamily;
3430 win32u_mbtowc( &ansi_cp, font32->lfFaceName, LF_FACESIZE, font16->lfFaceName,
3431 strlen( font16->lfFaceName ));
3432 font32->lfFaceName[LF_FACESIZE-1] = 0;
3435 static void get_real_fontname( LOGFONTW *lf, WCHAR fullname[LF_FACESIZE] )
3437 struct font_enum_entry enum_entry;
3438 ULONG count = sizeof(enum_entry);
3439 HDC hdc;
3441 hdc = get_display_dc();
3442 NtGdiEnumFonts( hdc, 0, 0, lstrlenW( lf->lfFaceName ), lf->lfFaceName, lf->lfCharSet,
3443 &count, &enum_entry );
3444 release_display_dc( hdc );
3446 if (count)
3447 lstrcpyW( fullname, enum_entry.lf.elfFullName );
3448 else
3449 lstrcpyW( fullname, lf->lfFaceName );
3452 LONG get_char_dimensions( HDC hdc, TEXTMETRICW *metric, int *height )
3454 SIZE sz;
3455 static const WCHAR abcdW[] =
3456 {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3457 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3458 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
3460 if (metric && !NtGdiGetTextMetricsW( hdc, metric, 0 )) return 0;
3462 if (!NtGdiGetTextExtentExW( hdc, abcdW, ARRAYSIZE(abcdW), 0, NULL, NULL, &sz, 0 ))
3463 return 0;
3465 if (height) *height = sz.cy;
3466 return (sz.cx / 26 + 1) / 2;
3469 /* get text metrics and/or "average" char width of the specified logfont
3470 * for the specified dc */
3471 static void get_text_metr_size( HDC hdc, LOGFONTW *lf, TEXTMETRICW *metric, UINT *psz )
3473 HFONT hfont, hfontsav;
3474 TEXTMETRICW tm;
3475 UINT ret;
3476 if (!metric) metric = &tm;
3477 hfont = NtGdiHfontCreate( lf, sizeof(*lf), 0, 0, NULL );
3478 if (!hfont || !(hfontsav = NtGdiSelectFont( hdc, hfont )))
3480 metric->tmHeight = -1;
3481 if (psz) *psz = 10;
3482 if (hfont) NtGdiDeleteObjectApp( hfont );
3483 return;
3485 ret = get_char_dimensions( hdc, metric, NULL );
3486 if (psz) *psz = ret ? ret : 10;
3487 NtGdiSelectFont( hdc, hfontsav );
3488 NtGdiDeleteObjectApp( hfont );
3491 DWORD get_dialog_base_units(void)
3493 static int cx, cy;
3495 if (!cx)
3497 HDC hdc;
3499 if ((hdc = NtUserGetDC( 0 )))
3501 cx = get_char_dimensions( hdc, NULL, &cy );
3502 NtUserReleaseDC( 0, hdc );
3504 TRACE( "base units = %d,%d\n", cx, cy );
3507 return MAKELONG( muldiv( cx, get_system_dpi(), USER_DEFAULT_SCREEN_DPI ),
3508 muldiv( cy, get_system_dpi(), USER_DEFAULT_SCREEN_DPI ));
3511 /* adjust some of the raw values found in the registry */
3512 static void normalize_nonclientmetrics( NONCLIENTMETRICSW *pncm)
3514 TEXTMETRICW tm;
3515 HDC hdc = get_display_dc();
3517 if( pncm->iBorderWidth < 1) pncm->iBorderWidth = 1;
3518 if( pncm->iCaptionWidth < 8) pncm->iCaptionWidth = 8;
3519 if( pncm->iScrollWidth < 8) pncm->iScrollWidth = 8;
3520 if( pncm->iScrollHeight < 8) pncm->iScrollHeight = 8;
3522 /* adjust some heights to the corresponding font */
3523 get_text_metr_size( hdc, &pncm->lfMenuFont, &tm, NULL);
3524 pncm->iMenuHeight = max( pncm->iMenuHeight, 2 + tm.tmHeight + tm.tmExternalLeading );
3525 get_text_metr_size( hdc, &pncm->lfCaptionFont, &tm, NULL);
3526 pncm->iCaptionHeight = max( pncm->iCaptionHeight, 2 + tm.tmHeight);
3527 get_text_metr_size( hdc, &pncm->lfSmCaptionFont, &tm, NULL);
3528 pncm->iSmCaptionHeight = max( pncm->iSmCaptionHeight, 2 + tm.tmHeight);
3529 release_display_dc( hdc );
3532 /* load a font (binary) parameter from the registry */
3533 static BOOL get_font_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
3535 LOGFONTW font;
3537 if (!ptr_param) return FALSE;
3539 if (!entry->hdr.loaded)
3541 switch (load_entry( &entry->hdr, &font, sizeof(font) ))
3543 case sizeof(font):
3544 if (font.lfHeight > 0) /* positive height value means points ( inch/72 ) */
3545 font.lfHeight = -muldiv( font.lfHeight, USER_DEFAULT_SCREEN_DPI, 72 );
3546 entry->font.val = font;
3547 break;
3548 case sizeof(LOGFONT16): /* win9x-winME format */
3549 logfont16to32( (LOGFONT16 *)&font, &entry->font.val );
3550 if (entry->font.val.lfHeight > 0)
3551 entry->font.val.lfHeight = -muldiv( entry->font.val.lfHeight, USER_DEFAULT_SCREEN_DPI, 72 );
3552 break;
3553 default:
3554 WARN( "Unknown format in key %s value %s\n",
3555 debugstr_a( parameter_key_names[entry->hdr.base_key] ),
3556 debugstr_a( entry->hdr.regval ));
3557 /* fall through */
3558 case 0: /* use the default GUI font */
3559 NtGdiExtGetObjectW( GetStockObject( DEFAULT_GUI_FONT ), sizeof(font), &font );
3560 font.lfHeight = map_from_system_dpi( font.lfHeight );
3561 font.lfWeight = entry->font.weight;
3562 entry->font.val = font;
3563 break;
3565 get_real_fontname( &entry->font.val, entry->font.fullname );
3566 entry->hdr.loaded = TRUE;
3568 font = entry->font.val;
3569 font.lfHeight = map_to_dpi( font.lfHeight, dpi );
3570 lstrcpyW( font.lfFaceName, entry->font.fullname );
3571 *(LOGFONTW *)ptr_param = font;
3572 return TRUE;
3575 /* set a font (binary) parameter in the registry */
3576 static BOOL set_font_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
3578 LOGFONTW font;
3579 WCHAR *ptr;
3581 memcpy( &font, ptr_param, sizeof(font) );
3582 /* zero pad the end of lfFaceName so we don't save uninitialised data */
3583 for (ptr = font.lfFaceName; ptr < font.lfFaceName + LF_FACESIZE && *ptr; ptr++);
3584 if (ptr < font.lfFaceName + LF_FACESIZE)
3585 memset( ptr, 0, (font.lfFaceName + LF_FACESIZE - ptr) * sizeof(WCHAR) );
3586 if (font.lfHeight < 0) font.lfHeight = map_from_system_dpi( font.lfHeight );
3588 if (!save_entry( &entry->hdr, &font, sizeof(font), REG_BINARY, flags )) return FALSE;
3589 entry->font.val = font;
3590 get_real_fontname( &entry->font.val, entry->font.fullname );
3591 entry->hdr.loaded = TRUE;
3592 return TRUE;
3595 /* initialize a font (binary) parameter */
3596 static BOOL init_font_entry( union sysparam_all_entry *entry )
3598 NtGdiExtGetObjectW( GetStockObject( DEFAULT_GUI_FONT ), sizeof(entry->font.val), &entry->font.val );
3599 entry->font.val.lfHeight = map_from_system_dpi( entry->font.val.lfHeight );
3600 entry->font.val.lfWeight = entry->font.weight;
3601 get_real_fontname( &entry->font.val, entry->font.fullname );
3602 return init_entry( &entry->hdr, &entry->font.val, sizeof(entry->font.val), REG_BINARY );
3605 /* get a user pref parameter in the registry */
3606 static BOOL get_userpref_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT dpi )
3608 union sysparam_all_entry *parent_entry = entry->pref.parent;
3609 BYTE prefs[8];
3611 if (!ptr_param) return FALSE;
3613 if (!parent_entry->hdr.get( parent_entry, sizeof(prefs), prefs, dpi )) return FALSE;
3614 *(BOOL *)ptr_param = (prefs[entry->pref.offset] & entry->pref.mask) != 0;
3615 return TRUE;
3618 /* set a user pref parameter in the registry */
3619 static BOOL set_userpref_entry( union sysparam_all_entry *entry, UINT int_param, void *ptr_param, UINT flags )
3621 union sysparam_all_entry *parent_entry = entry->pref.parent;
3622 BYTE prefs[8];
3624 parent_entry->hdr.loaded = FALSE; /* force loading it again */
3625 if (!parent_entry->hdr.get( parent_entry, sizeof(prefs), prefs, get_system_dpi() )) return FALSE;
3627 if (PtrToUlong( ptr_param )) prefs[entry->pref.offset] |= entry->pref.mask;
3628 else prefs[entry->pref.offset] &= ~entry->pref.mask;
3630 return parent_entry->hdr.set( parent_entry, sizeof(prefs), prefs, flags );
3633 static BOOL get_entry_dpi( void *ptr, UINT int_param, void *ptr_param, UINT dpi )
3635 union sysparam_all_entry *entry = ptr;
3636 return entry->hdr.get( entry, int_param, ptr_param, dpi );
3639 static BOOL get_entry( void *ptr, UINT int_param, void *ptr_param )
3641 return get_entry_dpi( ptr, int_param, ptr_param, get_system_dpi() );
3644 static BOOL set_entry( void *ptr, UINT int_param, void *ptr_param, UINT flags )
3646 union sysparam_all_entry *entry = ptr;
3647 return entry->hdr.set( entry, int_param, ptr_param, flags );
3650 #define UINT_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
3651 { .uint = { { get_uint_entry, set_uint_entry, init_uint_entry, base, reg }, (val) } }
3653 #define UINT_ENTRY_MIRROR(name,val,base,reg,mirror_base) union sysparam_all_entry entry_##name = \
3654 { .uint = { { get_uint_entry, set_uint_entry, init_uint_entry, base, reg, mirror_base, reg }, (val) } }
3656 #define INT_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
3657 { .uint = { { get_uint_entry, set_int_entry, init_int_entry, base, reg }, (val) } }
3659 #define BOOL_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
3660 { .bool = { { get_bool_entry, set_bool_entry, init_bool_entry, base, reg }, (val) } }
3662 #define BOOL_ENTRY_MIRROR(name,val,base,reg,mirror_base) union sysparam_all_entry entry_##name = \
3663 { .bool = { { get_bool_entry, set_bool_entry, init_bool_entry, base, reg, mirror_base, reg }, (val) } }
3665 #define TWIPS_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
3666 { .uint = { { get_twips_entry, set_twips_entry, init_int_entry, base, reg }, (val) } }
3668 #define YESNO_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
3669 { .bool = { { get_yesno_entry, set_yesno_entry, init_yesno_entry, base, reg }, (val) } }
3671 #define DWORD_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
3672 { .dword = { { get_dword_entry, set_dword_entry, init_dword_entry, base, reg }, (val) } }
3674 #define BINARY_ENTRY(name,data,base,reg) union sysparam_all_entry entry_##name = \
3675 { .bin = { { get_binary_entry, set_binary_entry, init_binary_entry, base, reg }, data, sizeof(data) } }
3677 #define PATH_ENTRY(name,base,reg,buffer) union sysparam_all_entry entry_##name = \
3678 { .path = { { get_path_entry, set_path_entry, init_path_entry, base, reg }, buffer } }
3680 #define FONT_ENTRY(name,weight,base,reg) union sysparam_all_entry entry_##name = \
3681 { .font = { { get_font_entry, set_font_entry, init_font_entry, base, reg }, (weight) } }
3683 #define USERPREF_ENTRY(name,offset,mask) union sysparam_all_entry entry_##name = \
3684 { .pref = { { get_userpref_entry, set_userpref_entry }, &entry_USERPREFERENCESMASK, (offset), (mask) } }
3686 static UINT_ENTRY( DRAGWIDTH, 4, DESKTOP_KEY, "DragWidth" );
3687 static UINT_ENTRY( DRAGHEIGHT, 4, DESKTOP_KEY, "DragHeight" );
3688 static UINT_ENTRY( DOUBLECLICKTIME, 500, MOUSE_KEY, "DoubleClickSpeed" );
3689 static UINT_ENTRY( FONTSMOOTHING, 2, DESKTOP_KEY, "FontSmoothing" );
3690 static UINT_ENTRY( GRIDGRANULARITY, 0, DESKTOP_KEY, "GridGranularity" );
3691 static UINT_ENTRY( KEYBOARDDELAY, 1, KEYBOARD_KEY, "KeyboardDelay" );
3692 static UINT_ENTRY( KEYBOARDSPEED, 31, KEYBOARD_KEY, "KeyboardSpeed" );
3693 static UINT_ENTRY( MENUSHOWDELAY, 400, DESKTOP_KEY, "MenuShowDelay" );
3694 static UINT_ENTRY( MINARRANGE, ARW_HIDE, METRICS_KEY, "MinArrange" );
3695 static UINT_ENTRY( MINHORZGAP, 0, METRICS_KEY, "MinHorzGap" );
3696 static UINT_ENTRY( MINVERTGAP, 0, METRICS_KEY, "MinVertGap" );
3697 static UINT_ENTRY( MINWIDTH, 154, METRICS_KEY, "MinWidth" );
3698 static UINT_ENTRY( MOUSEHOVERHEIGHT, 4, MOUSE_KEY, "MouseHoverHeight" );
3699 static UINT_ENTRY( MOUSEHOVERTIME, 400, MOUSE_KEY, "MouseHoverTime" );
3700 static UINT_ENTRY( MOUSEHOVERWIDTH, 4, MOUSE_KEY, "MouseHoverWidth" );
3701 static UINT_ENTRY( MOUSESPEED, 10, MOUSE_KEY, "MouseSensitivity" );
3702 static UINT_ENTRY( MOUSETRAILS, 0, MOUSE_KEY, "MouseTrails" );
3703 static UINT_ENTRY( SCREENSAVETIMEOUT, 300, DESKTOP_KEY, "ScreenSaveTimeOut" );
3704 static UINT_ENTRY( WHEELSCROLLCHARS, 3, DESKTOP_KEY, "WheelScrollChars" );
3705 static UINT_ENTRY( WHEELSCROLLLINES, 3, DESKTOP_KEY, "WheelScrollLines" );
3706 static UINT_ENTRY_MIRROR( DOUBLECLKHEIGHT, 4, MOUSE_KEY, "DoubleClickHeight", DESKTOP_KEY );
3707 static UINT_ENTRY_MIRROR( DOUBLECLKWIDTH, 4, MOUSE_KEY, "DoubleClickWidth", DESKTOP_KEY );
3708 static UINT_ENTRY_MIRROR( MENUDROPALIGNMENT, 0, DESKTOP_KEY, "MenuDropAlignment", VERSION_KEY );
3710 static INT_ENTRY( MOUSETHRESHOLD1, 6, MOUSE_KEY, "MouseThreshold1" );
3711 static INT_ENTRY( MOUSETHRESHOLD2, 10, MOUSE_KEY, "MouseThreshold2" );
3712 static INT_ENTRY( MOUSEACCELERATION, 1, MOUSE_KEY, "MouseSpeed" );
3714 static BOOL_ENTRY( BLOCKSENDINPUTRESETS, FALSE, DESKTOP_KEY, "BlockSendInputResets" );
3715 static BOOL_ENTRY( DRAGFULLWINDOWS, FALSE, DESKTOP_KEY, "DragFullWindows" );
3716 static BOOL_ENTRY( KEYBOARDPREF, TRUE, KEYBOARDPREF_KEY, "On" );
3717 static BOOL_ENTRY( LOWPOWERACTIVE, FALSE, DESKTOP_KEY, "LowPowerActive" );
3718 static BOOL_ENTRY( MOUSEBUTTONSWAP, FALSE, MOUSE_KEY, "SwapMouseButtons" );
3719 static BOOL_ENTRY( POWEROFFACTIVE, FALSE, DESKTOP_KEY, "PowerOffActive" );
3720 static BOOL_ENTRY( SCREENREADER, FALSE, SCREENREADER_KEY, "On" );
3721 static BOOL_ENTRY( SCREENSAVEACTIVE, TRUE, DESKTOP_KEY, "ScreenSaveActive" );
3722 static BOOL_ENTRY( SCREENSAVERRUNNING, FALSE, DESKTOP_KEY, "WINE_ScreenSaverRunning" ); /* FIXME - real value */
3723 static BOOL_ENTRY( SHOWSOUNDS, FALSE, SHOWSOUNDS_KEY, "On" );
3724 static BOOL_ENTRY( SNAPTODEFBUTTON, FALSE, MOUSE_KEY, "SnapToDefaultButton" );
3725 static BOOL_ENTRY_MIRROR( ICONTITLEWRAP, TRUE, DESKTOP_KEY, "IconTitleWrap", METRICS_KEY );
3726 static BOOL_ENTRY( AUDIODESC_ON, FALSE, AUDIODESC_KEY, "On" );
3728 static TWIPS_ENTRY( BORDER, -15, METRICS_KEY, "BorderWidth" );
3729 static TWIPS_ENTRY( CAPTIONHEIGHT, -270, METRICS_KEY, "CaptionHeight" );
3730 static TWIPS_ENTRY( CAPTIONWIDTH, -270, METRICS_KEY, "CaptionWidth" );
3731 static TWIPS_ENTRY( ICONHORIZONTALSPACING, -1125, METRICS_KEY, "IconSpacing" );
3732 static TWIPS_ENTRY( ICONVERTICALSPACING, -1125, METRICS_KEY, "IconVerticalSpacing" );
3733 static TWIPS_ENTRY( MENUHEIGHT, -270, METRICS_KEY, "MenuHeight" );
3734 static TWIPS_ENTRY( MENUWIDTH, -270, METRICS_KEY, "MenuWidth" );
3735 static TWIPS_ENTRY( PADDEDBORDERWIDTH, 0, METRICS_KEY, "PaddedBorderWidth" );
3736 static TWIPS_ENTRY( SCROLLHEIGHT, -240, METRICS_KEY, "ScrollHeight" );
3737 static TWIPS_ENTRY( SCROLLWIDTH, -240, METRICS_KEY, "ScrollWidth" );
3738 static TWIPS_ENTRY( SMCAPTIONHEIGHT, -225, METRICS_KEY, "SmCaptionHeight" );
3739 static TWIPS_ENTRY( SMCAPTIONWIDTH, -225, METRICS_KEY, "SmCaptionWidth" );
3741 static YESNO_ENTRY( BEEP, TRUE, SOUND_KEY, "Beep" );
3743 static DWORD_ENTRY( ACTIVEWINDOWTRACKING, 0, MOUSE_KEY, "ActiveWindowTracking" );
3744 static DWORD_ENTRY( ACTIVEWNDTRKTIMEOUT, 0, DESKTOP_KEY, "ActiveWndTrackTimeout" );
3745 static DWORD_ENTRY( CARETWIDTH, 1, DESKTOP_KEY, "CaretWidth" );
3746 static DWORD_ENTRY( DPISCALINGVER, 0, DESKTOP_KEY, "DpiScalingVer" );
3747 static DWORD_ENTRY( FOCUSBORDERHEIGHT, 1, DESKTOP_KEY, "FocusBorderHeight" );
3748 static DWORD_ENTRY( FOCUSBORDERWIDTH, 1, DESKTOP_KEY, "FocusBorderWidth" );
3749 static DWORD_ENTRY( FONTSMOOTHINGCONTRAST, 0, DESKTOP_KEY, "FontSmoothingGamma" );
3750 static DWORD_ENTRY( FONTSMOOTHINGORIENTATION, FE_FONTSMOOTHINGORIENTATIONRGB, DESKTOP_KEY, "FontSmoothingOrientation" );
3751 static DWORD_ENTRY( FONTSMOOTHINGTYPE, FE_FONTSMOOTHINGSTANDARD, DESKTOP_KEY, "FontSmoothingType" );
3752 static DWORD_ENTRY( FOREGROUNDFLASHCOUNT, 3, DESKTOP_KEY, "ForegroundFlashCount" );
3753 static DWORD_ENTRY( FOREGROUNDLOCKTIMEOUT, 0, DESKTOP_KEY, "ForegroundLockTimeout" );
3754 static DWORD_ENTRY( LOGPIXELS, 0, DESKTOP_KEY, "LogPixels" );
3755 static DWORD_ENTRY( MOUSECLICKLOCKTIME, 1200, DESKTOP_KEY, "ClickLockTime" );
3756 static DWORD_ENTRY( AUDIODESC_LOCALE, 0, AUDIODESC_KEY, "Locale" );
3758 static WCHAR desk_pattern_path[MAX_PATH];
3759 static WCHAR desk_wallpaper_path[MAX_PATH];
3760 static PATH_ENTRY( DESKPATTERN, DESKTOP_KEY, "Pattern", desk_pattern_path );
3761 static PATH_ENTRY( DESKWALLPAPER, DESKTOP_KEY, "Wallpaper", desk_wallpaper_path );
3763 static BYTE user_prefs[8] = { 0x30, 0x00, 0x00, 0x80, 0x12, 0x00, 0x00, 0x00 };
3764 static BINARY_ENTRY( USERPREFERENCESMASK, user_prefs, DESKTOP_KEY, "UserPreferencesMask" );
3766 static FONT_ENTRY( CAPTIONLOGFONT, FW_BOLD, METRICS_KEY, "CaptionFont" );
3767 static FONT_ENTRY( ICONTITLELOGFONT, FW_NORMAL, METRICS_KEY, "IconFont" );
3768 static FONT_ENTRY( MENULOGFONT, FW_NORMAL, METRICS_KEY, "MenuFont" );
3769 static FONT_ENTRY( MESSAGELOGFONT, FW_NORMAL, METRICS_KEY, "MessageFont" );
3770 static FONT_ENTRY( SMCAPTIONLOGFONT, FW_NORMAL, METRICS_KEY, "SmCaptionFont" );
3771 static FONT_ENTRY( STATUSLOGFONT, FW_NORMAL, METRICS_KEY, "StatusFont" );
3773 static USERPREF_ENTRY( MENUANIMATION, 0, 0x02 );
3774 static USERPREF_ENTRY( COMBOBOXANIMATION, 0, 0x04 );
3775 static USERPREF_ENTRY( LISTBOXSMOOTHSCROLLING, 0, 0x08 );
3776 static USERPREF_ENTRY( GRADIENTCAPTIONS, 0, 0x10 );
3777 static USERPREF_ENTRY( KEYBOARDCUES, 0, 0x20 );
3778 static USERPREF_ENTRY( ACTIVEWNDTRKZORDER, 0, 0x40 );
3779 static USERPREF_ENTRY( HOTTRACKING, 0, 0x80 );
3780 static USERPREF_ENTRY( MENUFADE, 1, 0x02 );
3781 static USERPREF_ENTRY( SELECTIONFADE, 1, 0x04 );
3782 static USERPREF_ENTRY( TOOLTIPANIMATION, 1, 0x08 );
3783 static USERPREF_ENTRY( TOOLTIPFADE, 1, 0x10 );
3784 static USERPREF_ENTRY( CURSORSHADOW, 1, 0x20 );
3785 static USERPREF_ENTRY( MOUSESONAR, 1, 0x40 );
3786 static USERPREF_ENTRY( MOUSECLICKLOCK, 1, 0x80 );
3787 static USERPREF_ENTRY( MOUSEVANISH, 2, 0x01 );
3788 static USERPREF_ENTRY( FLATMENU, 2, 0x02 );
3789 static USERPREF_ENTRY( DROPSHADOW, 2, 0x04 );
3790 static USERPREF_ENTRY( UIEFFECTS, 3, 0x80 );
3791 static USERPREF_ENTRY( DISABLEOVERLAPPEDCONTENT, 4, 0x01 );
3792 static USERPREF_ENTRY( CLIENTAREAANIMATION, 4, 0x02 );
3793 static USERPREF_ENTRY( CLEARTYPE, 4, 0x10 );
3794 static USERPREF_ENTRY( SPEECHRECOGNITION, 4, 0x20 );
3796 /* System parameter indexes */
3797 enum spi_index
3799 SPI_SETWORKAREA_IDX,
3800 SPI_INDEX_COUNT
3803 /* indicators whether system parameter value is loaded */
3804 static char spi_loaded[SPI_INDEX_COUNT];
3806 static struct sysparam_rgb_entry system_colors[] =
3808 #define RGB_ENTRY(name,val,reg) { { get_rgb_entry, set_rgb_entry, init_rgb_entry, COLORS_KEY, reg }, (val) }
3809 RGB_ENTRY( COLOR_SCROLLBAR, RGB(212, 208, 200), "Scrollbar" ),
3810 RGB_ENTRY( COLOR_BACKGROUND, RGB(58, 110, 165), "Background" ),
3811 RGB_ENTRY( COLOR_ACTIVECAPTION, RGB(10, 36, 106), "ActiveTitle" ),
3812 RGB_ENTRY( COLOR_INACTIVECAPTION, RGB(128, 128, 128), "InactiveTitle" ),
3813 RGB_ENTRY( COLOR_MENU, RGB(212, 208, 200), "Menu" ),
3814 RGB_ENTRY( COLOR_WINDOW, RGB(255, 255, 255), "Window" ),
3815 RGB_ENTRY( COLOR_WINDOWFRAME, RGB(0, 0, 0), "WindowFrame" ),
3816 RGB_ENTRY( COLOR_MENUTEXT, RGB(0, 0, 0), "MenuText" ),
3817 RGB_ENTRY( COLOR_WINDOWTEXT, RGB(0, 0, 0), "WindowText" ),
3818 RGB_ENTRY( COLOR_CAPTIONTEXT, RGB(255, 255, 255), "TitleText" ),
3819 RGB_ENTRY( COLOR_ACTIVEBORDER, RGB(212, 208, 200), "ActiveBorder" ),
3820 RGB_ENTRY( COLOR_INACTIVEBORDER, RGB(212, 208, 200), "InactiveBorder" ),
3821 RGB_ENTRY( COLOR_APPWORKSPACE, RGB(128, 128, 128), "AppWorkSpace" ),
3822 RGB_ENTRY( COLOR_HIGHLIGHT, RGB(10, 36, 106), "Hilight" ),
3823 RGB_ENTRY( COLOR_HIGHLIGHTTEXT, RGB(255, 255, 255), "HilightText" ),
3824 RGB_ENTRY( COLOR_BTNFACE, RGB(212, 208, 200), "ButtonFace" ),
3825 RGB_ENTRY( COLOR_BTNSHADOW, RGB(128, 128, 128), "ButtonShadow" ),
3826 RGB_ENTRY( COLOR_GRAYTEXT, RGB(128, 128, 128), "GrayText" ),
3827 RGB_ENTRY( COLOR_BTNTEXT, RGB(0, 0, 0), "ButtonText" ),
3828 RGB_ENTRY( COLOR_INACTIVECAPTIONTEXT, RGB(212, 208, 200), "InactiveTitleText" ),
3829 RGB_ENTRY( COLOR_BTNHIGHLIGHT, RGB(255, 255, 255), "ButtonHilight" ),
3830 RGB_ENTRY( COLOR_3DDKSHADOW, RGB(64, 64, 64), "ButtonDkShadow" ),
3831 RGB_ENTRY( COLOR_3DLIGHT, RGB(212, 208, 200), "ButtonLight" ),
3832 RGB_ENTRY( COLOR_INFOTEXT, RGB(0, 0, 0), "InfoText" ),
3833 RGB_ENTRY( COLOR_INFOBK, RGB(255, 255, 225), "InfoWindow" ),
3834 RGB_ENTRY( COLOR_ALTERNATEBTNFACE, RGB(181, 181, 181), "ButtonAlternateFace" ),
3835 RGB_ENTRY( COLOR_HOTLIGHT, RGB(0, 0, 200), "HotTrackingColor" ),
3836 RGB_ENTRY( COLOR_GRADIENTACTIVECAPTION, RGB(166, 202, 240), "GradientActiveTitle" ),
3837 RGB_ENTRY( COLOR_GRADIENTINACTIVECAPTION, RGB(192, 192, 192), "GradientInactiveTitle" ),
3838 RGB_ENTRY( COLOR_MENUHILIGHT, RGB(10, 36, 106), "MenuHilight" ),
3839 RGB_ENTRY( COLOR_MENUBAR, RGB(212, 208, 200), "MenuBar" )
3840 #undef RGB_ENTRY
3843 /* entries that are initialized by default in the registry */
3844 static union sysparam_all_entry * const default_entries[] =
3846 (union sysparam_all_entry *)&entry_ACTIVEWINDOWTRACKING,
3847 (union sysparam_all_entry *)&entry_ACTIVEWNDTRKTIMEOUT,
3848 (union sysparam_all_entry *)&entry_BEEP,
3849 (union sysparam_all_entry *)&entry_BLOCKSENDINPUTRESETS,
3850 (union sysparam_all_entry *)&entry_BORDER,
3851 (union sysparam_all_entry *)&entry_CAPTIONHEIGHT,
3852 (union sysparam_all_entry *)&entry_CAPTIONWIDTH,
3853 (union sysparam_all_entry *)&entry_CARETWIDTH,
3854 (union sysparam_all_entry *)&entry_DESKWALLPAPER,
3855 (union sysparam_all_entry *)&entry_DOUBLECLICKTIME,
3856 (union sysparam_all_entry *)&entry_DOUBLECLKHEIGHT,
3857 (union sysparam_all_entry *)&entry_DOUBLECLKWIDTH,
3858 (union sysparam_all_entry *)&entry_DRAGFULLWINDOWS,
3859 (union sysparam_all_entry *)&entry_DRAGHEIGHT,
3860 (union sysparam_all_entry *)&entry_DRAGWIDTH,
3861 (union sysparam_all_entry *)&entry_FOCUSBORDERHEIGHT,
3862 (union sysparam_all_entry *)&entry_FOCUSBORDERWIDTH,
3863 (union sysparam_all_entry *)&entry_FONTSMOOTHING,
3864 (union sysparam_all_entry *)&entry_FONTSMOOTHINGCONTRAST,
3865 (union sysparam_all_entry *)&entry_FONTSMOOTHINGORIENTATION,
3866 (union sysparam_all_entry *)&entry_FONTSMOOTHINGTYPE,
3867 (union sysparam_all_entry *)&entry_FOREGROUNDFLASHCOUNT,
3868 (union sysparam_all_entry *)&entry_FOREGROUNDLOCKTIMEOUT,
3869 (union sysparam_all_entry *)&entry_ICONHORIZONTALSPACING,
3870 (union sysparam_all_entry *)&entry_ICONTITLEWRAP,
3871 (union sysparam_all_entry *)&entry_ICONVERTICALSPACING,
3872 (union sysparam_all_entry *)&entry_KEYBOARDDELAY,
3873 (union sysparam_all_entry *)&entry_KEYBOARDPREF,
3874 (union sysparam_all_entry *)&entry_KEYBOARDSPEED,
3875 (union sysparam_all_entry *)&entry_LOWPOWERACTIVE,
3876 (union sysparam_all_entry *)&entry_MENUHEIGHT,
3877 (union sysparam_all_entry *)&entry_MENUSHOWDELAY,
3878 (union sysparam_all_entry *)&entry_MENUWIDTH,
3879 (union sysparam_all_entry *)&entry_MOUSEACCELERATION,
3880 (union sysparam_all_entry *)&entry_MOUSEBUTTONSWAP,
3881 (union sysparam_all_entry *)&entry_MOUSECLICKLOCKTIME,
3882 (union sysparam_all_entry *)&entry_MOUSEHOVERHEIGHT,
3883 (union sysparam_all_entry *)&entry_MOUSEHOVERTIME,
3884 (union sysparam_all_entry *)&entry_MOUSEHOVERWIDTH,
3885 (union sysparam_all_entry *)&entry_MOUSESPEED,
3886 (union sysparam_all_entry *)&entry_MOUSETHRESHOLD1,
3887 (union sysparam_all_entry *)&entry_MOUSETHRESHOLD2,
3888 (union sysparam_all_entry *)&entry_PADDEDBORDERWIDTH,
3889 (union sysparam_all_entry *)&entry_SCREENREADER,
3890 (union sysparam_all_entry *)&entry_SCROLLHEIGHT,
3891 (union sysparam_all_entry *)&entry_SCROLLWIDTH,
3892 (union sysparam_all_entry *)&entry_SHOWSOUNDS,
3893 (union sysparam_all_entry *)&entry_SMCAPTIONHEIGHT,
3894 (union sysparam_all_entry *)&entry_SMCAPTIONWIDTH,
3895 (union sysparam_all_entry *)&entry_SNAPTODEFBUTTON,
3896 (union sysparam_all_entry *)&entry_USERPREFERENCESMASK,
3897 (union sysparam_all_entry *)&entry_WHEELSCROLLCHARS,
3898 (union sysparam_all_entry *)&entry_WHEELSCROLLLINES,
3899 (union sysparam_all_entry *)&entry_AUDIODESC_LOCALE,
3900 (union sysparam_all_entry *)&entry_AUDIODESC_ON,
3903 void sysparams_init(void)
3906 DWORD i, dispos, dpi_scaling;
3907 WCHAR layout[KL_NAMELENGTH];
3908 pthread_mutexattr_t attr;
3909 HKEY hkey;
3911 static const WCHAR software_wineW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e'};
3912 static const WCHAR temporary_system_parametersW[] =
3913 {'T','e','m','p','o','r','a','r','y',' ','S','y','s','t','e','m',' ',
3914 'P','a','r','a','m','e','t','e','r','s'};
3915 static const WCHAR oneW[] = {'1',0};
3916 static const WCHAR kl_preloadW[] =
3917 {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d'};
3919 pthread_mutexattr_init( &attr );
3920 pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
3921 pthread_mutex_init( &user_mutex, &attr );
3922 pthread_mutexattr_destroy( &attr );
3924 if ((hkey = reg_create_key( hkcu_key, kl_preloadW, sizeof(kl_preloadW), 0, NULL )))
3926 if (NtUserGetKeyboardLayoutName( layout ))
3927 set_reg_value( hkey, oneW, REG_SZ, (const BYTE *)layout,
3928 (lstrlenW(layout) + 1) * sizeof(WCHAR) );
3929 NtClose( hkey );
3932 /* this one must be non-volatile */
3933 if (!(hkey = reg_create_key( hkcu_key, software_wineW, sizeof(software_wineW), 0, NULL )))
3935 ERR("Can't create wine registry branch\n");
3936 return;
3939 /* @@ Wine registry key: HKCU\Software\Wine\Temporary System Parameters */
3940 if (!(volatile_base_key = reg_create_key( hkey, temporary_system_parametersW,
3941 sizeof(temporary_system_parametersW),
3942 REG_OPTION_VOLATILE, &dispos )))
3943 ERR("Can't create non-permanent wine registry branch\n");
3945 NtClose( hkey );
3947 config_key = reg_create_key( NULL, config_keyW, sizeof(config_keyW), 0, NULL );
3949 get_dword_entry( (union sysparam_all_entry *)&entry_LOGPIXELS, 0, &system_dpi, 0 );
3950 if (!system_dpi) /* check fallback key */
3952 static const WCHAR log_pixelsW[] = {'L','o','g','P','i','x','e','l','s',0};
3953 static const WCHAR software_fontsW[] =
3954 {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s'};
3956 if ((hkey = reg_open_key( config_key, software_fontsW, sizeof(software_fontsW) )))
3958 char buffer[offsetof(KEY_VALUE_PARTIAL_INFORMATION, Data[sizeof(DWORD)])];
3959 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
3961 if (query_reg_value( hkey, log_pixelsW, value, sizeof(buffer) ) && value->Type == REG_DWORD)
3962 system_dpi = *(const DWORD *)value->Data;
3963 NtClose( hkey );
3966 if (!system_dpi) system_dpi = USER_DEFAULT_SCREEN_DPI;
3968 /* FIXME: what do the DpiScalingVer flags mean? */
3969 get_dword_entry( (union sysparam_all_entry *)&entry_DPISCALINGVER, 0, &dpi_scaling, 0 );
3970 if (!dpi_scaling) NtUserSetProcessDpiAwarenessContext( NTUSER_DPI_PER_MONITOR_AWARE, 0 );
3972 if (volatile_base_key && dispos == REG_CREATED_NEW_KEY) /* first process, initialize entries */
3974 for (i = 0; i < ARRAY_SIZE( default_entries ); i++)
3975 default_entries[i]->hdr.init( default_entries[i] );
3979 static BOOL update_desktop_wallpaper(void)
3981 /* FIXME: move implementation from user32 */
3982 entry_DESKWALLPAPER.hdr.loaded = entry_DESKPATTERN.hdr.loaded = FALSE;
3983 return TRUE;
3986 /***********************************************************************
3987 * NtUserSystemParametersInfoForDpi (win32u.@)
3989 BOOL WINAPI NtUserSystemParametersInfoForDpi( UINT action, UINT val, PVOID ptr, UINT winini, UINT dpi )
3991 BOOL ret = FALSE;
3993 switch (action)
3995 case SPI_GETICONTITLELOGFONT:
3996 ret = get_entry_dpi( &entry_ICONTITLELOGFONT, val, ptr, dpi );
3997 break;
3998 case SPI_GETNONCLIENTMETRICS:
4000 NONCLIENTMETRICSW *ncm = ptr;
4002 if (!ncm) break;
4003 ret = get_entry_dpi( &entry_BORDER, 0, &ncm->iBorderWidth, dpi ) &&
4004 get_entry_dpi( &entry_SCROLLWIDTH, 0, &ncm->iScrollWidth, dpi ) &&
4005 get_entry_dpi( &entry_SCROLLHEIGHT, 0, &ncm->iScrollHeight, dpi ) &&
4006 get_entry_dpi( &entry_CAPTIONWIDTH, 0, &ncm->iCaptionWidth, dpi ) &&
4007 get_entry_dpi( &entry_CAPTIONHEIGHT, 0, &ncm->iCaptionHeight, dpi ) &&
4008 get_entry_dpi( &entry_CAPTIONLOGFONT, 0, &ncm->lfCaptionFont, dpi ) &&
4009 get_entry_dpi( &entry_SMCAPTIONWIDTH, 0, &ncm->iSmCaptionWidth, dpi ) &&
4010 get_entry_dpi( &entry_SMCAPTIONHEIGHT, 0, &ncm->iSmCaptionHeight, dpi ) &&
4011 get_entry_dpi( &entry_SMCAPTIONLOGFONT, 0, &ncm->lfSmCaptionFont, dpi ) &&
4012 get_entry_dpi( &entry_MENUWIDTH, 0, &ncm->iMenuWidth, dpi ) &&
4013 get_entry_dpi( &entry_MENUHEIGHT, 0, &ncm->iMenuHeight, dpi ) &&
4014 get_entry_dpi( &entry_MENULOGFONT, 0, &ncm->lfMenuFont, dpi ) &&
4015 get_entry_dpi( &entry_STATUSLOGFONT, 0, &ncm->lfStatusFont, dpi ) &&
4016 get_entry_dpi( &entry_MESSAGELOGFONT, 0, &ncm->lfMessageFont, dpi );
4017 if (ret && ncm->cbSize == sizeof(NONCLIENTMETRICSW))
4018 ret = get_entry_dpi( &entry_PADDEDBORDERWIDTH, 0, &ncm->iPaddedBorderWidth, dpi );
4019 normalize_nonclientmetrics( ncm );
4020 break;
4022 case SPI_GETICONMETRICS:
4024 ICONMETRICSW *im = ptr;
4025 if (im && im->cbSize == sizeof(*im))
4026 ret = get_entry_dpi( &entry_ICONHORIZONTALSPACING, 0, &im->iHorzSpacing, dpi ) &&
4027 get_entry_dpi( &entry_ICONVERTICALSPACING, 0, &im->iVertSpacing, dpi ) &&
4028 get_entry_dpi( &entry_ICONTITLEWRAP, 0, &im->iTitleWrap, dpi ) &&
4029 get_entry_dpi( &entry_ICONTITLELOGFONT, 0, &im->lfFont, dpi );
4030 break;
4032 default:
4033 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
4034 break;
4036 return ret;
4039 /***********************************************************************
4040 * NtUserSystemParametersInfo (win32u.@)
4042 * Each system parameter has flag which shows whether the parameter
4043 * is loaded or not. Parameters, stored directly in SysParametersInfo are
4044 * loaded from registry only when they are requested and the flag is
4045 * "false", after the loading the flag is set to "true". On interprocess
4046 * notification of the parameter change the corresponding parameter flag is
4047 * set to "false". The parameter value will be reloaded when it is requested
4048 * the next time.
4049 * Parameters, backed by or depend on GetSystemMetrics are processed
4050 * differently. These parameters are always loaded. They are reloaded right
4051 * away on interprocess change notification. We can't do lazy loading because
4052 * we don't want to complicate GetSystemMetrics.
4053 * Parameters backed by driver settings are read from corresponding setting.
4054 * On the parameter change request the setting is changed. Interprocess change
4055 * notifications are ignored.
4056 * When parameter value is updated the changed value is stored in permanent
4057 * registry branch if saving is requested. Otherwise it is stored
4058 * in temporary branch
4060 * Some SPI values can also be stored as Twips values in the registry,
4061 * don't forget the conversion!
4063 BOOL WINAPI NtUserSystemParametersInfo( UINT action, UINT val, void *ptr, UINT winini )
4065 #define WINE_SPI_FIXME(x) \
4066 case x: \
4068 static BOOL warn = TRUE; \
4069 if (warn) \
4071 warn = FALSE; \
4072 FIXME( "Unimplemented action: %u (%s)\n", x, #x ); \
4075 RtlSetLastWin32Error( ERROR_INVALID_SPI_VALUE ); \
4076 ret = FALSE; \
4077 break
4078 #define WINE_SPI_WARN(x) \
4079 case x: \
4080 WARN( "Ignored action: %u (%s)\n", x, #x ); \
4081 ret = TRUE; \
4082 break
4084 BOOL ret = user_driver->pSystemParametersInfo( action, val, ptr, winini );
4085 unsigned spi_idx = 0;
4087 if (!ret) switch (action)
4089 case SPI_GETBEEP:
4090 ret = get_entry( &entry_BEEP, val, ptr );
4091 break;
4092 case SPI_SETBEEP:
4093 ret = set_entry( &entry_BEEP, val, ptr, winini );
4094 break;
4095 case SPI_GETMOUSE:
4096 ret = get_entry( &entry_MOUSETHRESHOLD1, val, (INT *)ptr ) &&
4097 get_entry( &entry_MOUSETHRESHOLD2, val, (INT *)ptr + 1 ) &&
4098 get_entry( &entry_MOUSEACCELERATION, val, (INT *)ptr + 2 );
4099 break;
4100 case SPI_SETMOUSE:
4101 ret = set_entry( &entry_MOUSETHRESHOLD1, ((INT *)ptr)[0], ptr, winini ) &&
4102 set_entry( &entry_MOUSETHRESHOLD2, ((INT *)ptr)[1], ptr, winini ) &&
4103 set_entry( &entry_MOUSEACCELERATION, ((INT *)ptr)[2], ptr, winini );
4104 break;
4105 case SPI_GETBORDER:
4106 ret = get_entry( &entry_BORDER, val, ptr );
4107 if (*(INT*)ptr < 1) *(INT*)ptr = 1;
4108 break;
4109 case SPI_SETBORDER:
4110 ret = set_entry( &entry_BORDER, val, ptr, winini );
4111 break;
4112 case SPI_GETKEYBOARDSPEED:
4113 ret = get_entry( &entry_KEYBOARDSPEED, val, ptr );
4114 break;
4115 case SPI_SETKEYBOARDSPEED:
4116 if (val > 31) val = 31;
4117 ret = set_entry( &entry_KEYBOARDSPEED, val, ptr, winini );
4118 break;
4120 WINE_SPI_WARN(SPI_LANGDRIVER); /* not implemented in Windows */
4122 case SPI_ICONHORIZONTALSPACING:
4123 if (ptr != NULL)
4124 ret = get_entry( &entry_ICONHORIZONTALSPACING, val, ptr );
4125 else
4127 int min_val = map_to_dpi( 32, get_system_dpi() );
4128 ret = set_entry( &entry_ICONHORIZONTALSPACING, max( min_val, val ), ptr, winini );
4130 break;
4131 case SPI_GETSCREENSAVETIMEOUT:
4132 ret = get_entry( &entry_SCREENSAVETIMEOUT, val, ptr );
4133 break;
4134 case SPI_SETSCREENSAVETIMEOUT:
4135 ret = set_entry( &entry_SCREENSAVETIMEOUT, val, ptr, winini );
4136 break;
4137 case SPI_GETSCREENSAVEACTIVE:
4138 ret = get_entry( &entry_SCREENSAVEACTIVE, val, ptr );
4139 break;
4140 case SPI_SETSCREENSAVEACTIVE:
4141 ret = set_entry( &entry_SCREENSAVEACTIVE, val, ptr, winini );
4142 break;
4143 case SPI_GETGRIDGRANULARITY:
4144 ret = get_entry( &entry_GRIDGRANULARITY, val, ptr );
4145 break;
4146 case SPI_SETGRIDGRANULARITY:
4147 ret = set_entry( &entry_GRIDGRANULARITY, val, ptr, winini );
4148 break;
4149 case SPI_SETDESKWALLPAPER:
4150 if (!ptr || set_entry( &entry_DESKWALLPAPER, val, ptr, winini ))
4151 ret = update_desktop_wallpaper();
4152 break;
4153 case SPI_SETDESKPATTERN:
4154 if (!ptr || set_entry( &entry_DESKPATTERN, val, ptr, winini ))
4155 ret = update_desktop_wallpaper();
4156 break;
4157 case SPI_GETKEYBOARDDELAY:
4158 ret = get_entry( &entry_KEYBOARDDELAY, val, ptr );
4159 break;
4160 case SPI_SETKEYBOARDDELAY:
4161 ret = set_entry( &entry_KEYBOARDDELAY, val, ptr, winini );
4162 break;
4163 case SPI_ICONVERTICALSPACING:
4164 if (ptr != NULL)
4165 ret = get_entry( &entry_ICONVERTICALSPACING, val, ptr );
4166 else
4168 int min_val = map_to_dpi( 32, get_system_dpi() );
4169 ret = set_entry( &entry_ICONVERTICALSPACING, max( min_val, val ), ptr, winini );
4171 break;
4172 case SPI_GETICONTITLEWRAP:
4173 ret = get_entry( &entry_ICONTITLEWRAP, val, ptr );
4174 break;
4175 case SPI_SETICONTITLEWRAP:
4176 ret = set_entry( &entry_ICONTITLEWRAP, val, ptr, winini );
4177 break;
4178 case SPI_GETMENUDROPALIGNMENT:
4179 ret = get_entry( &entry_MENUDROPALIGNMENT, val, ptr );
4180 break;
4181 case SPI_SETMENUDROPALIGNMENT:
4182 ret = set_entry( &entry_MENUDROPALIGNMENT, val, ptr, winini );
4183 break;
4184 case SPI_SETDOUBLECLKWIDTH:
4185 ret = set_entry( &entry_DOUBLECLKWIDTH, val, ptr, winini );
4186 break;
4187 case SPI_SETDOUBLECLKHEIGHT:
4188 ret = set_entry( &entry_DOUBLECLKHEIGHT, val, ptr, winini );
4189 break;
4190 case SPI_GETICONTITLELOGFONT:
4191 ret = get_entry( &entry_ICONTITLELOGFONT, val, ptr );
4192 break;
4193 case SPI_SETDOUBLECLICKTIME:
4194 ret = set_entry( &entry_DOUBLECLICKTIME, val, ptr, winini );
4195 break;
4196 case SPI_SETMOUSEBUTTONSWAP:
4197 ret = set_entry( &entry_MOUSEBUTTONSWAP, val, ptr, winini );
4198 break;
4199 case SPI_SETICONTITLELOGFONT:
4200 ret = set_entry( &entry_ICONTITLELOGFONT, val, ptr, winini );
4201 break;
4202 case SPI_GETFASTTASKSWITCH:
4203 if (!ptr) return FALSE;
4204 *(BOOL *)ptr = TRUE;
4205 ret = TRUE;
4206 break;
4207 case SPI_SETFASTTASKSWITCH:
4208 /* the action is disabled */
4209 ret = FALSE;
4210 break;
4211 case SPI_SETDRAGFULLWINDOWS:
4212 ret = set_entry( &entry_DRAGFULLWINDOWS, val, ptr, winini );
4213 break;
4214 case SPI_GETDRAGFULLWINDOWS:
4215 ret = get_entry( &entry_DRAGFULLWINDOWS, val, ptr );
4216 break;
4217 case SPI_GETNONCLIENTMETRICS:
4219 NONCLIENTMETRICSW *nm = ptr;
4220 int padded_border;
4222 if (!ptr) return FALSE;
4224 ret = get_entry( &entry_BORDER, 0, &nm->iBorderWidth ) &&
4225 get_entry( &entry_PADDEDBORDERWIDTH, 0, &padded_border ) &&
4226 get_entry( &entry_SCROLLWIDTH, 0, &nm->iScrollWidth ) &&
4227 get_entry( &entry_SCROLLHEIGHT, 0, &nm->iScrollHeight ) &&
4228 get_entry( &entry_CAPTIONWIDTH, 0, &nm->iCaptionWidth ) &&
4229 get_entry( &entry_CAPTIONHEIGHT, 0, &nm->iCaptionHeight ) &&
4230 get_entry( &entry_CAPTIONLOGFONT, 0, &nm->lfCaptionFont ) &&
4231 get_entry( &entry_SMCAPTIONWIDTH, 0, &nm->iSmCaptionWidth ) &&
4232 get_entry( &entry_SMCAPTIONHEIGHT, 0, &nm->iSmCaptionHeight ) &&
4233 get_entry( &entry_SMCAPTIONLOGFONT, 0, &nm->lfSmCaptionFont ) &&
4234 get_entry( &entry_MENUWIDTH, 0, &nm->iMenuWidth ) &&
4235 get_entry( &entry_MENUHEIGHT, 0, &nm->iMenuHeight ) &&
4236 get_entry( &entry_MENULOGFONT, 0, &nm->lfMenuFont ) &&
4237 get_entry( &entry_STATUSLOGFONT, 0, &nm->lfStatusFont ) &&
4238 get_entry( &entry_MESSAGELOGFONT, 0, &nm->lfMessageFont );
4239 if (ret)
4241 nm->iBorderWidth += padded_border;
4242 if (nm->cbSize == sizeof(NONCLIENTMETRICSW)) nm->iPaddedBorderWidth = 0;
4244 normalize_nonclientmetrics( nm );
4245 break;
4247 case SPI_SETNONCLIENTMETRICS:
4249 LPNONCLIENTMETRICSW nm = ptr;
4250 int padded_border;
4252 if (nm && (nm->cbSize == sizeof(NONCLIENTMETRICSW) ||
4253 nm->cbSize == FIELD_OFFSET(NONCLIENTMETRICSW, iPaddedBorderWidth)))
4255 get_entry( &entry_PADDEDBORDERWIDTH, 0, &padded_border );
4257 ret = set_entry( &entry_BORDER, nm->iBorderWidth - padded_border, NULL, winini ) &&
4258 set_entry( &entry_SCROLLWIDTH, nm->iScrollWidth, NULL, winini ) &&
4259 set_entry( &entry_SCROLLHEIGHT, nm->iScrollHeight, NULL, winini ) &&
4260 set_entry( &entry_CAPTIONWIDTH, nm->iCaptionWidth, NULL, winini ) &&
4261 set_entry( &entry_CAPTIONHEIGHT, nm->iCaptionHeight, NULL, winini ) &&
4262 set_entry( &entry_SMCAPTIONWIDTH, nm->iSmCaptionWidth, NULL, winini ) &&
4263 set_entry( &entry_SMCAPTIONHEIGHT, nm->iSmCaptionHeight, NULL, winini ) &&
4264 set_entry( &entry_MENUWIDTH, nm->iMenuWidth, NULL, winini ) &&
4265 set_entry( &entry_MENUHEIGHT, nm->iMenuHeight, NULL, winini ) &&
4266 set_entry( &entry_MENULOGFONT, 0, &nm->lfMenuFont, winini ) &&
4267 set_entry( &entry_CAPTIONLOGFONT, 0, &nm->lfCaptionFont, winini ) &&
4268 set_entry( &entry_SMCAPTIONLOGFONT, 0, &nm->lfSmCaptionFont, winini ) &&
4269 set_entry( &entry_STATUSLOGFONT, 0, &nm->lfStatusFont, winini ) &&
4270 set_entry( &entry_MESSAGELOGFONT, 0, &nm->lfMessageFont, winini );
4272 break;
4274 case SPI_GETMINIMIZEDMETRICS:
4276 MINIMIZEDMETRICS *mm = ptr;
4277 if (mm && mm->cbSize == sizeof(*mm)) {
4278 ret = get_entry( &entry_MINWIDTH, 0, &mm->iWidth ) &&
4279 get_entry( &entry_MINHORZGAP, 0, &mm->iHorzGap ) &&
4280 get_entry( &entry_MINVERTGAP, 0, &mm->iVertGap ) &&
4281 get_entry( &entry_MINARRANGE, 0, &mm->iArrange );
4282 mm->iWidth = max( 0, mm->iWidth );
4283 mm->iHorzGap = max( 0, mm->iHorzGap );
4284 mm->iVertGap = max( 0, mm->iVertGap );
4285 mm->iArrange &= 0x0f;
4287 break;
4289 case SPI_SETMINIMIZEDMETRICS:
4291 MINIMIZEDMETRICS *mm = ptr;
4292 if (mm && mm->cbSize == sizeof(*mm))
4293 ret = set_entry( &entry_MINWIDTH, max( 0, mm->iWidth ), NULL, winini ) &&
4294 set_entry( &entry_MINHORZGAP, max( 0, mm->iHorzGap ), NULL, winini ) &&
4295 set_entry( &entry_MINVERTGAP, max( 0, mm->iVertGap ), NULL, winini ) &&
4296 set_entry( &entry_MINARRANGE, mm->iArrange & 0x0f, NULL, winini );
4297 break;
4299 case SPI_GETICONMETRICS:
4301 ICONMETRICSW *icon = ptr;
4302 if(icon && icon->cbSize == sizeof(*icon))
4304 ret = get_entry( &entry_ICONHORIZONTALSPACING, 0, &icon->iHorzSpacing ) &&
4305 get_entry( &entry_ICONVERTICALSPACING, 0, &icon->iVertSpacing ) &&
4306 get_entry( &entry_ICONTITLEWRAP, 0, &icon->iTitleWrap ) &&
4307 get_entry( &entry_ICONTITLELOGFONT, 0, &icon->lfFont );
4309 break;
4311 case SPI_SETICONMETRICS:
4313 ICONMETRICSW *icon = ptr;
4314 if (icon && icon->cbSize == sizeof(*icon))
4315 ret = set_entry( &entry_ICONVERTICALSPACING, max(32,icon->iVertSpacing), NULL, winini ) &&
4316 set_entry( &entry_ICONHORIZONTALSPACING, max(32,icon->iHorzSpacing), NULL, winini ) &&
4317 set_entry( &entry_ICONTITLEWRAP, icon->iTitleWrap, NULL, winini ) &&
4318 set_entry( &entry_ICONTITLELOGFONT, 0, &icon->lfFont, winini );
4319 break;
4321 case SPI_SETWORKAREA:
4323 if (!ptr) return FALSE;
4324 spi_idx = SPI_SETWORKAREA_IDX;
4325 work_area = *(RECT*)ptr;
4326 spi_loaded[spi_idx] = TRUE;
4327 ret = TRUE;
4328 break;
4330 case SPI_GETWORKAREA:
4332 if (!ptr) return FALSE;
4334 spi_idx = SPI_SETWORKAREA_IDX;
4335 if (!spi_loaded[spi_idx])
4337 struct monitor *monitor;
4339 if (!lock_display_devices()) return FALSE;
4341 LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
4343 if (!(monitor->flags & MONITORINFOF_PRIMARY)) continue;
4344 work_area = monitor->rc_work;
4345 break;
4348 unlock_display_devices();
4349 spi_loaded[spi_idx] = TRUE;
4351 *(RECT *)ptr = map_dpi_rect( work_area, system_dpi, get_thread_dpi() );
4352 ret = TRUE;
4353 TRACE("work area %s\n", wine_dbgstr_rect( &work_area ));
4354 break;
4357 WINE_SPI_FIXME(SPI_SETPENWINDOWS);
4359 case SPI_GETFILTERKEYS:
4361 LPFILTERKEYS filter_keys = ptr;
4362 WARN("SPI_GETFILTERKEYS not fully implemented\n");
4363 if (filter_keys && filter_keys->cbSize == sizeof(FILTERKEYS))
4365 /* Indicate that no FilterKeys feature available */
4366 filter_keys->dwFlags = 0;
4367 filter_keys->iWaitMSec = 0;
4368 filter_keys->iDelayMSec = 0;
4369 filter_keys->iRepeatMSec = 0;
4370 filter_keys->iBounceMSec = 0;
4371 ret = TRUE;
4373 break;
4375 WINE_SPI_FIXME(SPI_SETFILTERKEYS);
4377 case SPI_GETTOGGLEKEYS:
4379 LPTOGGLEKEYS toggle_keys = ptr;
4380 WARN("SPI_GETTOGGLEKEYS not fully implemented\n");
4381 if (toggle_keys && toggle_keys->cbSize == sizeof(TOGGLEKEYS))
4383 /* Indicate that no ToggleKeys feature available */
4384 toggle_keys->dwFlags = 0;
4385 ret = TRUE;
4387 break;
4390 WINE_SPI_FIXME(SPI_SETTOGGLEKEYS);
4392 case SPI_GETMOUSEKEYS:
4394 MOUSEKEYS *mouse_keys = ptr;
4395 WARN("SPI_GETMOUSEKEYS not fully implemented\n");
4396 if (mouse_keys && mouse_keys->cbSize == sizeof(MOUSEKEYS))
4398 /* Indicate that no MouseKeys feature available */
4399 mouse_keys->dwFlags = 0;
4400 mouse_keys->iMaxSpeed = 360;
4401 mouse_keys->iTimeToMaxSpeed = 1000;
4402 mouse_keys->iCtrlSpeed = 0;
4403 mouse_keys->dwReserved1 = 0;
4404 mouse_keys->dwReserved2 = 0;
4405 ret = TRUE;
4407 break;
4410 WINE_SPI_FIXME(SPI_SETMOUSEKEYS);
4412 case SPI_GETSHOWSOUNDS:
4413 ret = get_entry( &entry_SHOWSOUNDS, val, ptr );
4414 break;
4415 case SPI_SETSHOWSOUNDS:
4416 ret = set_entry( &entry_SHOWSOUNDS, val, ptr, winini );
4417 break;
4418 case SPI_GETSTICKYKEYS:
4420 STICKYKEYS *sticky_keys = ptr;
4421 WARN("SPI_GETSTICKYKEYS not fully implemented\n");
4422 if (sticky_keys && sticky_keys->cbSize == sizeof(STICKYKEYS))
4424 /* Indicate that no StickyKeys feature available */
4425 sticky_keys->dwFlags = 0;
4426 ret = TRUE;
4428 break;
4431 WINE_SPI_FIXME(SPI_SETSTICKYKEYS);
4433 case SPI_GETACCESSTIMEOUT:
4435 ACCESSTIMEOUT *access_timeout = ptr;
4436 WARN("SPI_GETACCESSTIMEOUT not fully implemented\n");
4437 if (access_timeout && access_timeout->cbSize == sizeof(ACCESSTIMEOUT))
4439 /* Indicate that no accessibility features timeout is available */
4440 access_timeout->dwFlags = 0;
4441 access_timeout->iTimeOutMSec = 0;
4442 ret = TRUE;
4444 break;
4447 WINE_SPI_FIXME(SPI_SETACCESSTIMEOUT);
4449 case SPI_GETSERIALKEYS:
4451 LPSERIALKEYSW serial_keys = ptr;
4452 WARN("SPI_GETSERIALKEYS not fully implemented\n");
4453 if (serial_keys && serial_keys->cbSize == sizeof(SERIALKEYSW))
4455 /* Indicate that no SerialKeys feature available */
4456 serial_keys->dwFlags = 0;
4457 serial_keys->lpszActivePort = NULL;
4458 serial_keys->lpszPort = NULL;
4459 serial_keys->iBaudRate = 0;
4460 serial_keys->iPortState = 0;
4461 ret = TRUE;
4463 break;
4466 WINE_SPI_FIXME(SPI_SETSERIALKEYS);
4468 case SPI_GETSOUNDSENTRY:
4470 SOUNDSENTRYW *sound_sentry = ptr;
4471 WARN("SPI_GETSOUNDSENTRY not fully implemented\n");
4472 if (sound_sentry && sound_sentry->cbSize == sizeof(SOUNDSENTRYW))
4474 /* Indicate that no SoundSentry feature available */
4475 sound_sentry->dwFlags = 0;
4476 sound_sentry->iFSTextEffect = 0;
4477 sound_sentry->iFSTextEffectMSec = 0;
4478 sound_sentry->iFSTextEffectColorBits = 0;
4479 sound_sentry->iFSGrafEffect = 0;
4480 sound_sentry->iFSGrafEffectMSec = 0;
4481 sound_sentry->iFSGrafEffectColor = 0;
4482 sound_sentry->iWindowsEffect = 0;
4483 sound_sentry->iWindowsEffectMSec = 0;
4484 sound_sentry->lpszWindowsEffectDLL = 0;
4485 sound_sentry->iWindowsEffectOrdinal = 0;
4486 ret = TRUE;
4488 break;
4491 WINE_SPI_FIXME(SPI_SETSOUNDSENTRY);
4493 case SPI_GETHIGHCONTRAST:
4495 HIGHCONTRASTW *high_contrast = ptr;
4496 WARN("SPI_GETHIGHCONTRAST not fully implemented\n");
4497 if (high_contrast && high_contrast->cbSize == sizeof(HIGHCONTRASTW))
4499 /* Indicate that no high contrast feature available */
4500 high_contrast->dwFlags = 0;
4501 high_contrast->lpszDefaultScheme = NULL;
4502 ret = TRUE;
4504 break;
4507 WINE_SPI_FIXME(SPI_SETHIGHCONTRAST);
4509 case SPI_GETKEYBOARDPREF:
4510 ret = get_entry( &entry_KEYBOARDPREF, val, ptr );
4511 break;
4512 case SPI_SETKEYBOARDPREF:
4513 ret = set_entry( &entry_KEYBOARDPREF, val, ptr, winini );
4514 break;
4515 case SPI_GETSCREENREADER:
4516 ret = get_entry( &entry_SCREENREADER, val, ptr );
4517 break;
4518 case SPI_SETSCREENREADER:
4519 ret = set_entry( &entry_SCREENREADER, val, ptr, winini );
4520 break;
4522 case SPI_GETANIMATION:
4524 ANIMATIONINFO *anim_info = ptr;
4526 /* Tell it "disabled" */
4527 if (anim_info && anim_info->cbSize == sizeof(ANIMATIONINFO))
4529 /* Minimize and restore animation is disabled (nonzero == enabled) */
4530 anim_info->iMinAnimate = 0;
4531 ret = TRUE;
4533 break;
4536 WINE_SPI_WARN(SPI_SETANIMATION);
4538 case SPI_GETFONTSMOOTHING:
4539 ret = get_entry( &entry_FONTSMOOTHING, val, ptr );
4540 if (ret) *(UINT *)ptr = (*(UINT *)ptr != 0);
4541 break;
4542 case SPI_SETFONTSMOOTHING:
4543 val = val ? 2 : 0; /* Win NT4/2k/XP behavior */
4544 ret = set_entry( &entry_FONTSMOOTHING, val, ptr, winini );
4545 break;
4546 case SPI_SETDRAGWIDTH:
4547 ret = set_entry( &entry_DRAGWIDTH, val, ptr, winini );
4548 break;
4549 case SPI_SETDRAGHEIGHT:
4550 ret = set_entry( &entry_DRAGHEIGHT, val, ptr, winini );
4551 break;
4553 WINE_SPI_FIXME(SPI_SETHANDHELD);
4554 WINE_SPI_FIXME(SPI_GETLOWPOWERTIMEOUT);
4555 WINE_SPI_FIXME(SPI_GETPOWEROFFTIMEOUT);
4556 WINE_SPI_FIXME(SPI_SETLOWPOWERTIMEOUT);
4557 WINE_SPI_FIXME(SPI_SETPOWEROFFTIMEOUT);
4559 case SPI_GETLOWPOWERACTIVE:
4560 ret = get_entry( &entry_LOWPOWERACTIVE, val, ptr );
4561 break;
4562 case SPI_SETLOWPOWERACTIVE:
4563 ret = set_entry( &entry_LOWPOWERACTIVE, val, ptr, winini );
4564 break;
4565 case SPI_GETPOWEROFFACTIVE:
4566 ret = get_entry( &entry_POWEROFFACTIVE, val, ptr );
4567 break;
4568 case SPI_SETPOWEROFFACTIVE:
4569 ret = set_entry( &entry_POWEROFFACTIVE, val, ptr, winini );
4570 break;
4572 WINE_SPI_FIXME(SPI_SETCURSORS);
4573 WINE_SPI_FIXME(SPI_SETICONS);
4575 case SPI_GETDEFAULTINPUTLANG:
4576 ret = NtUserGetKeyboardLayout(0) != 0;
4577 break;
4579 WINE_SPI_FIXME(SPI_SETDEFAULTINPUTLANG);
4580 WINE_SPI_FIXME(SPI_SETLANGTOGGLE);
4582 case SPI_GETWINDOWSEXTENSION:
4583 WARN( "pretend no support for Win9x Plus! for now.\n" );
4584 ret = FALSE; /* yes, this is the result value */
4585 break;
4586 case SPI_SETMOUSETRAILS:
4587 ret = set_entry( &entry_MOUSETRAILS, val, ptr, winini );
4588 break;
4589 case SPI_GETMOUSETRAILS:
4590 ret = get_entry( &entry_MOUSETRAILS, val, ptr );
4591 break;
4592 case SPI_GETSNAPTODEFBUTTON:
4593 ret = get_entry( &entry_SNAPTODEFBUTTON, val, ptr );
4594 break;
4595 case SPI_SETSNAPTODEFBUTTON:
4596 ret = set_entry( &entry_SNAPTODEFBUTTON, val, ptr, winini );
4597 break;
4598 case SPI_SETSCREENSAVERRUNNING:
4599 ret = set_entry( &entry_SCREENSAVERRUNNING, val, ptr, winini );
4600 break;
4601 case SPI_GETMOUSEHOVERWIDTH:
4602 ret = get_entry( &entry_MOUSEHOVERWIDTH, val, ptr );
4603 break;
4604 case SPI_SETMOUSEHOVERWIDTH:
4605 ret = set_entry( &entry_MOUSEHOVERWIDTH, val, ptr, winini );
4606 break;
4607 case SPI_GETMOUSEHOVERHEIGHT:
4608 ret = get_entry( &entry_MOUSEHOVERHEIGHT, val, ptr );
4609 break;
4610 case SPI_SETMOUSEHOVERHEIGHT:
4611 ret = set_entry( &entry_MOUSEHOVERHEIGHT, val, ptr, winini );
4612 break;
4613 case SPI_GETMOUSEHOVERTIME:
4614 ret = get_entry( &entry_MOUSEHOVERTIME, val, ptr );
4615 break;
4616 case SPI_SETMOUSEHOVERTIME:
4617 ret = set_entry( &entry_MOUSEHOVERTIME, val, ptr, winini );
4618 break;
4619 case SPI_GETWHEELSCROLLLINES:
4620 ret = get_entry( &entry_WHEELSCROLLLINES, val, ptr );
4621 break;
4622 case SPI_SETWHEELSCROLLLINES:
4623 ret = set_entry( &entry_WHEELSCROLLLINES, val, ptr, winini );
4624 break;
4625 case SPI_GETMENUSHOWDELAY:
4626 ret = get_entry( &entry_MENUSHOWDELAY, val, ptr );
4627 break;
4628 case SPI_SETMENUSHOWDELAY:
4629 ret = set_entry( &entry_MENUSHOWDELAY, val, ptr, winini );
4630 break;
4631 case SPI_GETWHEELSCROLLCHARS:
4632 ret = get_entry( &entry_WHEELSCROLLCHARS, val, ptr );
4633 break;
4634 case SPI_SETWHEELSCROLLCHARS:
4635 ret = set_entry( &entry_WHEELSCROLLCHARS, val, ptr, winini );
4636 break;
4638 WINE_SPI_FIXME(SPI_GETSHOWIMEUI);
4639 WINE_SPI_FIXME(SPI_SETSHOWIMEUI);
4641 case SPI_GETMOUSESPEED:
4642 ret = get_entry( &entry_MOUSESPEED, val, ptr );
4643 break;
4644 case SPI_SETMOUSESPEED:
4645 ret = set_entry( &entry_MOUSESPEED, val, ptr, winini );
4646 break;
4647 case SPI_GETSCREENSAVERRUNNING:
4648 ret = get_entry( &entry_SCREENSAVERRUNNING, val, ptr );
4649 break;
4650 case SPI_GETDESKWALLPAPER:
4651 ret = get_entry( &entry_DESKWALLPAPER, val, ptr );
4652 break;
4653 case SPI_GETACTIVEWINDOWTRACKING:
4654 ret = get_entry( &entry_ACTIVEWINDOWTRACKING, val, ptr );
4655 break;
4656 case SPI_SETACTIVEWINDOWTRACKING:
4657 ret = set_entry( &entry_ACTIVEWINDOWTRACKING, val, ptr, winini );
4658 break;
4659 case SPI_GETMENUANIMATION:
4660 ret = get_entry( &entry_MENUANIMATION, val, ptr );
4661 break;
4662 case SPI_SETMENUANIMATION:
4663 ret = set_entry( &entry_MENUANIMATION, val, ptr, winini );
4664 break;
4665 case SPI_GETCOMBOBOXANIMATION:
4666 ret = get_entry( &entry_COMBOBOXANIMATION, val, ptr );
4667 break;
4668 case SPI_SETCOMBOBOXANIMATION:
4669 ret = set_entry( &entry_COMBOBOXANIMATION, val, ptr, winini );
4670 break;
4671 case SPI_GETLISTBOXSMOOTHSCROLLING:
4672 ret = get_entry( &entry_LISTBOXSMOOTHSCROLLING, val, ptr );
4673 break;
4674 case SPI_SETLISTBOXSMOOTHSCROLLING:
4675 ret = set_entry( &entry_LISTBOXSMOOTHSCROLLING, val, ptr, winini );
4676 break;
4677 case SPI_GETGRADIENTCAPTIONS:
4678 ret = get_entry( &entry_GRADIENTCAPTIONS, val, ptr );
4679 break;
4680 case SPI_SETGRADIENTCAPTIONS:
4681 ret = set_entry( &entry_GRADIENTCAPTIONS, val, ptr, winini );
4682 break;
4683 case SPI_GETKEYBOARDCUES:
4684 ret = get_entry( &entry_KEYBOARDCUES, val, ptr );
4685 break;
4686 case SPI_SETKEYBOARDCUES:
4687 ret = set_entry( &entry_KEYBOARDCUES, val, ptr, winini );
4688 break;
4689 case SPI_GETACTIVEWNDTRKZORDER:
4690 ret = get_entry( &entry_ACTIVEWNDTRKZORDER, val, ptr );
4691 break;
4692 case SPI_SETACTIVEWNDTRKZORDER:
4693 ret = set_entry( &entry_ACTIVEWNDTRKZORDER, val, ptr, winini );
4694 break;
4695 case SPI_GETHOTTRACKING:
4696 ret = get_entry( &entry_HOTTRACKING, val, ptr );
4697 break;
4698 case SPI_SETHOTTRACKING:
4699 ret = set_entry( &entry_HOTTRACKING, val, ptr, winini );
4700 break;
4701 case SPI_GETMENUFADE:
4702 ret = get_entry( &entry_MENUFADE, val, ptr );
4703 break;
4704 case SPI_SETMENUFADE:
4705 ret = set_entry( &entry_MENUFADE, val, ptr, winini );
4706 break;
4707 case SPI_GETSELECTIONFADE:
4708 ret = get_entry( &entry_SELECTIONFADE, val, ptr );
4709 break;
4710 case SPI_SETSELECTIONFADE:
4711 ret = set_entry( &entry_SELECTIONFADE, val, ptr, winini );
4712 break;
4713 case SPI_GETTOOLTIPANIMATION:
4714 ret = get_entry( &entry_TOOLTIPANIMATION, val, ptr );
4715 break;
4716 case SPI_SETTOOLTIPANIMATION:
4717 ret = set_entry( &entry_TOOLTIPANIMATION, val, ptr, winini );
4718 break;
4719 case SPI_GETTOOLTIPFADE:
4720 ret = get_entry( &entry_TOOLTIPFADE, val, ptr );
4721 break;
4722 case SPI_SETTOOLTIPFADE:
4723 ret = set_entry( &entry_TOOLTIPFADE, val, ptr, winini );
4724 break;
4725 case SPI_GETCURSORSHADOW:
4726 ret = get_entry( &entry_CURSORSHADOW, val, ptr );
4727 break;
4728 case SPI_SETCURSORSHADOW:
4729 ret = set_entry( &entry_CURSORSHADOW, val, ptr, winini );
4730 break;
4731 case SPI_GETMOUSESONAR:
4732 ret = get_entry( &entry_MOUSESONAR, val, ptr );
4733 break;
4734 case SPI_SETMOUSESONAR:
4735 ret = set_entry( &entry_MOUSESONAR, val, ptr, winini );
4736 break;
4737 case SPI_GETMOUSECLICKLOCK:
4738 ret = get_entry( &entry_MOUSECLICKLOCK, val, ptr );
4739 break;
4740 case SPI_SETMOUSECLICKLOCK:
4741 ret = set_entry( &entry_MOUSECLICKLOCK, val, ptr, winini );
4742 break;
4743 case SPI_GETMOUSEVANISH:
4744 ret = get_entry( &entry_MOUSEVANISH, val, ptr );
4745 break;
4746 case SPI_SETMOUSEVANISH:
4747 ret = set_entry( &entry_MOUSEVANISH, val, ptr, winini );
4748 break;
4749 case SPI_GETFLATMENU:
4750 ret = get_entry( &entry_FLATMENU, val, ptr );
4751 break;
4752 case SPI_SETFLATMENU:
4753 ret = set_entry( &entry_FLATMENU, val, ptr, winini );
4754 break;
4755 case SPI_GETDROPSHADOW:
4756 ret = get_entry( &entry_DROPSHADOW, val, ptr );
4757 break;
4758 case SPI_SETDROPSHADOW:
4759 ret = set_entry( &entry_DROPSHADOW, val, ptr, winini );
4760 break;
4761 case SPI_GETBLOCKSENDINPUTRESETS:
4762 ret = get_entry( &entry_BLOCKSENDINPUTRESETS, val, ptr );
4763 break;
4764 case SPI_SETBLOCKSENDINPUTRESETS:
4765 ret = set_entry( &entry_BLOCKSENDINPUTRESETS, val, ptr, winini );
4766 break;
4767 case SPI_GETUIEFFECTS:
4768 ret = get_entry( &entry_UIEFFECTS, val, ptr );
4769 break;
4770 case SPI_SETUIEFFECTS:
4771 /* FIXME: this probably should mask other UI effect values when unset */
4772 ret = set_entry( &entry_UIEFFECTS, val, ptr, winini );
4773 break;
4774 case SPI_GETDISABLEOVERLAPPEDCONTENT:
4775 ret = get_entry( &entry_DISABLEOVERLAPPEDCONTENT, val, ptr );
4776 break;
4777 case SPI_SETDISABLEOVERLAPPEDCONTENT:
4778 ret = set_entry( &entry_DISABLEOVERLAPPEDCONTENT, val, ptr, winini );
4779 break;
4780 case SPI_GETCLIENTAREAANIMATION:
4781 ret = get_entry( &entry_CLIENTAREAANIMATION, val, ptr );
4782 break;
4783 case SPI_SETCLIENTAREAANIMATION:
4784 ret = set_entry( &entry_CLIENTAREAANIMATION, val, ptr, winini );
4785 break;
4786 case SPI_GETCLEARTYPE:
4787 ret = get_entry( &entry_CLEARTYPE, val, ptr );
4788 break;
4789 case SPI_SETCLEARTYPE:
4790 ret = set_entry( &entry_CLEARTYPE, val, ptr, winini );
4791 break;
4792 case SPI_GETSPEECHRECOGNITION:
4793 ret = get_entry( &entry_SPEECHRECOGNITION, val, ptr );
4794 break;
4795 case SPI_SETSPEECHRECOGNITION:
4796 ret = set_entry( &entry_SPEECHRECOGNITION, val, ptr, winini );
4797 break;
4798 case SPI_GETFOREGROUNDLOCKTIMEOUT:
4799 ret = get_entry( &entry_FOREGROUNDLOCKTIMEOUT, val, ptr );
4800 break;
4801 case SPI_SETFOREGROUNDLOCKTIMEOUT:
4802 /* FIXME: this should check that the calling thread
4803 * is able to change the foreground window */
4804 ret = set_entry( &entry_FOREGROUNDLOCKTIMEOUT, val, ptr, winini );
4805 break;
4806 case SPI_GETACTIVEWNDTRKTIMEOUT:
4807 ret = get_entry( &entry_ACTIVEWNDTRKTIMEOUT, val, ptr );
4808 break;
4809 case SPI_SETACTIVEWNDTRKTIMEOUT:
4810 ret = get_entry( &entry_ACTIVEWNDTRKTIMEOUT, val, ptr );
4811 break;
4812 case SPI_GETFOREGROUNDFLASHCOUNT:
4813 ret = get_entry( &entry_FOREGROUNDFLASHCOUNT, val, ptr );
4814 break;
4815 case SPI_SETFOREGROUNDFLASHCOUNT:
4816 ret = set_entry( &entry_FOREGROUNDFLASHCOUNT, val, ptr, winini );
4817 break;
4818 case SPI_GETCARETWIDTH:
4819 ret = get_entry( &entry_CARETWIDTH, val, ptr );
4820 break;
4821 case SPI_SETCARETWIDTH:
4822 ret = set_entry( &entry_CARETWIDTH, val, ptr, winini );
4823 break;
4824 case SPI_GETMOUSECLICKLOCKTIME:
4825 ret = get_entry( &entry_MOUSECLICKLOCKTIME, val, ptr );
4826 break;
4827 case SPI_SETMOUSECLICKLOCKTIME:
4828 ret = set_entry( &entry_MOUSECLICKLOCKTIME, val, ptr, winini );
4829 break;
4830 case SPI_GETFONTSMOOTHINGTYPE:
4831 ret = get_entry( &entry_FONTSMOOTHINGTYPE, val, ptr );
4832 break;
4833 case SPI_SETFONTSMOOTHINGTYPE:
4834 ret = set_entry( &entry_FONTSMOOTHINGTYPE, val, ptr, winini );
4835 break;
4836 case SPI_GETFONTSMOOTHINGCONTRAST:
4837 ret = get_entry( &entry_FONTSMOOTHINGCONTRAST, val, ptr );
4838 break;
4839 case SPI_SETFONTSMOOTHINGCONTRAST:
4840 ret = set_entry( &entry_FONTSMOOTHINGCONTRAST, val, ptr, winini );
4841 break;
4842 case SPI_GETFOCUSBORDERWIDTH:
4843 ret = get_entry( &entry_FOCUSBORDERWIDTH, val, ptr );
4844 break;
4845 case SPI_GETFOCUSBORDERHEIGHT:
4846 ret = get_entry( &entry_FOCUSBORDERHEIGHT, val, ptr );
4847 break;
4848 case SPI_SETFOCUSBORDERWIDTH:
4849 ret = set_entry( &entry_FOCUSBORDERWIDTH, val, ptr, winini );
4850 break;
4851 case SPI_SETFOCUSBORDERHEIGHT:
4852 ret = set_entry( &entry_FOCUSBORDERHEIGHT, val, ptr, winini );
4853 break;
4854 case SPI_GETFONTSMOOTHINGORIENTATION:
4855 ret = get_entry( &entry_FONTSMOOTHINGORIENTATION, val, ptr );
4856 break;
4857 case SPI_SETFONTSMOOTHINGORIENTATION:
4858 ret = set_entry( &entry_FONTSMOOTHINGORIENTATION, val, ptr, winini );
4859 break;
4860 case SPI_GETAUDIODESCRIPTION:
4862 AUDIODESCRIPTION *audio = ptr;
4863 if (audio && audio->cbSize == sizeof(AUDIODESCRIPTION) && val == sizeof(AUDIODESCRIPTION) )
4865 ret = get_entry( &entry_AUDIODESC_ON, 0, &audio->Enabled ) &&
4866 get_entry( &entry_AUDIODESC_LOCALE, 0, &audio->Locale );
4868 break;
4870 case SPI_SETAUDIODESCRIPTION:
4872 AUDIODESCRIPTION *audio = ptr;
4873 if (audio && audio->cbSize == sizeof(AUDIODESCRIPTION) && val == sizeof(AUDIODESCRIPTION) )
4875 ret = set_entry( &entry_AUDIODESC_ON, 0, &audio->Enabled, winini) &&
4876 set_entry( &entry_AUDIODESC_LOCALE, 0, &audio->Locale, winini );
4878 break;
4880 default:
4881 FIXME( "Unknown action: %u\n", action );
4882 RtlSetLastWin32Error( ERROR_INVALID_SPI_VALUE );
4883 ret = FALSE;
4884 break;
4887 if (ret && (winini & SPIF_UPDATEINIFILE))
4889 static const WCHAR emptyW[1];
4890 if (winini & (SPIF_SENDWININICHANGE | SPIF_SENDCHANGE))
4891 send_message_timeout( HWND_BROADCAST, WM_SETTINGCHANGE, action, (LPARAM) emptyW,
4892 SMTO_ABORTIFHUNG, 2000, FALSE );
4894 TRACE( "(%u, %u, %p, %u) ret %d\n", action, val, ptr, winini, ret );
4895 return ret;
4897 #undef WINE_SPI_FIXME
4898 #undef WINE_SPI_WARN
4901 int get_system_metrics( int index )
4903 NONCLIENTMETRICSW ncm;
4904 MINIMIZEDMETRICS mm;
4905 ICONMETRICSW im;
4906 RECT rect;
4907 UINT ret;
4908 HDC hdc;
4910 /* some metrics are dynamic */
4911 switch (index)
4913 case SM_CXVSCROLL:
4914 case SM_CYHSCROLL:
4915 get_entry( &entry_SCROLLWIDTH, 0, &ret );
4916 return max( ret, 8 );
4917 case SM_CYCAPTION:
4918 ncm.cbSize = sizeof(ncm);
4919 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4920 return ncm.iCaptionHeight + 1;
4921 case SM_CXBORDER:
4922 case SM_CYBORDER:
4923 /* SM_C{X,Y}BORDER always returns 1 regardless of 'BorderWidth' value in registry */
4924 return 1;
4925 case SM_CXDLGFRAME:
4926 case SM_CYDLGFRAME:
4927 return 3;
4928 case SM_CYVTHUMB:
4929 case SM_CXHTHUMB:
4930 case SM_CYVSCROLL:
4931 case SM_CXHSCROLL:
4932 get_entry( &entry_SCROLLHEIGHT, 0, &ret );
4933 return max( ret, 8 );
4934 case SM_CXICON:
4935 case SM_CYICON:
4936 return map_to_dpi( 32, get_system_dpi() );
4937 case SM_CXCURSOR:
4938 case SM_CYCURSOR:
4939 ret = map_to_dpi( 32, get_system_dpi() );
4940 if (ret >= 64) return 64;
4941 if (ret >= 48) return 48;
4942 return 32;
4943 case SM_CYMENU:
4944 ncm.cbSize = sizeof(ncm);
4945 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4946 return ncm.iMenuHeight + 1;
4947 case SM_CXFULLSCREEN:
4948 /* see the remark for SM_CXMAXIMIZED, at least this formulation is correct */
4949 return get_system_metrics( SM_CXMAXIMIZED ) - 2 * get_system_metrics( SM_CXFRAME );
4950 case SM_CYFULLSCREEN:
4951 /* see the remark for SM_CYMAXIMIZED, at least this formulation is
4952 * correct */
4953 return get_system_metrics( SM_CYMAXIMIZED ) - get_system_metrics( SM_CYMIN );
4954 case SM_CYKANJIWINDOW:
4955 return 0;
4956 case SM_MOUSEPRESENT:
4957 return 1;
4958 case SM_DEBUG:
4959 return 0;
4960 case SM_SWAPBUTTON:
4961 get_entry( &entry_MOUSEBUTTONSWAP, 0, &ret );
4962 return ret;
4963 case SM_RESERVED1:
4964 case SM_RESERVED2:
4965 case SM_RESERVED3:
4966 case SM_RESERVED4:
4967 return 0;
4968 case SM_CXMIN:
4969 ncm.cbSize = sizeof(ncm);
4970 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4971 hdc = get_display_dc();
4972 get_text_metr_size( hdc, &ncm.lfCaptionFont, NULL, &ret );
4973 release_display_dc( hdc );
4974 return 3 * ncm.iCaptionWidth + ncm.iCaptionHeight + 4 * ret +
4975 2 * get_system_metrics( SM_CXFRAME ) + 4;
4976 case SM_CYMIN:
4977 return get_system_metrics( SM_CYCAPTION ) + 2 * get_system_metrics( SM_CYFRAME );
4978 case SM_CXSIZE:
4979 get_entry( &entry_CAPTIONWIDTH, 0, &ret );
4980 return max( ret, 8 );
4981 case SM_CYSIZE:
4982 ncm.cbSize = sizeof(ncm);
4983 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4984 return ncm.iCaptionHeight;
4985 case SM_CXFRAME:
4986 get_entry( &entry_BORDER, 0, &ret );
4987 ret = max( ret, 1 );
4988 return get_system_metrics( SM_CXDLGFRAME ) + ret;
4989 case SM_CYFRAME:
4990 get_entry( &entry_BORDER, 0, &ret );
4991 ret = max( ret, 1 );
4992 return get_system_metrics( SM_CYDLGFRAME ) + ret;
4993 case SM_CXMINTRACK:
4994 return get_system_metrics( SM_CXMIN );
4995 case SM_CYMINTRACK:
4996 return get_system_metrics( SM_CYMIN );
4997 case SM_CXDOUBLECLK:
4998 get_entry( &entry_DOUBLECLKWIDTH, 0, &ret );
4999 return ret;
5000 case SM_CYDOUBLECLK:
5001 get_entry( &entry_DOUBLECLKHEIGHT, 0, &ret );
5002 return ret;
5003 case SM_CXICONSPACING:
5004 im.cbSize = sizeof(im);
5005 NtUserSystemParametersInfo( SPI_GETICONMETRICS, sizeof(im), &im, 0 );
5006 return im.iHorzSpacing;
5007 case SM_CYICONSPACING:
5008 im.cbSize = sizeof(im);
5009 NtUserSystemParametersInfo( SPI_GETICONMETRICS, sizeof(im), &im, 0 );
5010 return im.iVertSpacing;
5011 case SM_MENUDROPALIGNMENT:
5012 NtUserSystemParametersInfo( SPI_GETMENUDROPALIGNMENT, 0, &ret, 0 );
5013 return ret;
5014 case SM_PENWINDOWS:
5015 return 0;
5016 case SM_DBCSENABLED:
5017 return ansi_cp.MaximumCharacterSize > 1;
5018 case SM_CMOUSEBUTTONS:
5019 return 3;
5020 case SM_SECURE:
5021 return 0;
5022 case SM_CXEDGE:
5023 return get_system_metrics( SM_CXBORDER ) + 1;
5024 case SM_CYEDGE:
5025 return get_system_metrics( SM_CYBORDER ) + 1;
5026 case SM_CXMINSPACING:
5027 mm.cbSize = sizeof(mm);
5028 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
5029 return get_system_metrics( SM_CXMINIMIZED ) + mm.iHorzGap;
5030 case SM_CYMINSPACING:
5031 mm.cbSize = sizeof(mm);
5032 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
5033 return get_system_metrics( SM_CYMINIMIZED ) + mm.iVertGap;
5034 case SM_CXSMICON:
5035 case SM_CYSMICON:
5036 return map_to_dpi( 16, get_system_dpi() ) & ~1;
5037 case SM_CYSMCAPTION:
5038 ncm.cbSize = sizeof(ncm);
5039 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
5040 return ncm.iSmCaptionHeight + 1;
5041 case SM_CXSMSIZE:
5042 get_entry( &entry_SMCAPTIONWIDTH, 0, &ret );
5043 return ret;
5044 case SM_CYSMSIZE:
5045 ncm.cbSize = sizeof(ncm);
5046 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
5047 return ncm.iSmCaptionHeight;
5048 case SM_CXMENUSIZE:
5049 get_entry( &entry_MENUWIDTH, 0, &ret );
5050 return ret;
5051 case SM_CYMENUSIZE:
5052 ncm.cbSize = sizeof(ncm);
5053 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
5054 return ncm.iMenuHeight;
5055 case SM_ARRANGE:
5056 mm.cbSize = sizeof(mm);
5057 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
5058 return mm.iArrange;
5059 case SM_CXMINIMIZED:
5060 mm.cbSize = sizeof(mm);
5061 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0 );
5062 return mm.iWidth + 6;
5063 case SM_CYMINIMIZED:
5064 ncm.cbSize = sizeof(ncm);
5065 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
5066 return ncm.iCaptionHeight + 6;
5067 case SM_CXMAXTRACK:
5068 return get_system_metrics( SM_CXVIRTUALSCREEN ) + 4 + 2 * get_system_metrics( SM_CXFRAME );
5069 case SM_CYMAXTRACK:
5070 return get_system_metrics( SM_CYVIRTUALSCREEN ) + 4 + 2 * get_system_metrics( SM_CYFRAME );
5071 case SM_CXMAXIMIZED:
5072 /* FIXME: subtract the width of any vertical application toolbars*/
5073 return get_system_metrics( SM_CXSCREEN ) + 2 * get_system_metrics( SM_CXFRAME );
5074 case SM_CYMAXIMIZED:
5075 /* FIXME: subtract the width of any horizontal application toolbars*/
5076 return get_system_metrics( SM_CYSCREEN ) + 2 * get_system_metrics( SM_CYCAPTION );
5077 case SM_NETWORK:
5078 return 3; /* FIXME */
5079 case SM_CLEANBOOT:
5080 return 0; /* 0 = ok, 1 = failsafe, 2 = failsafe + network */
5081 case SM_CXDRAG:
5082 get_entry( &entry_DRAGWIDTH, 0, &ret );
5083 return ret;
5084 case SM_CYDRAG:
5085 get_entry( &entry_DRAGHEIGHT, 0, &ret );
5086 return ret;
5087 case SM_SHOWSOUNDS:
5088 get_entry( &entry_SHOWSOUNDS, 0, &ret );
5089 return ret;
5090 case SM_CXMENUCHECK:
5091 case SM_CYMENUCHECK:
5093 TEXTMETRICW tm;
5094 ncm.cbSize = sizeof(ncm);
5095 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
5096 hdc = get_display_dc();
5097 get_text_metr_size( hdc, &ncm.lfMenuFont, &tm, NULL );
5098 release_display_dc( hdc );
5099 return tm.tmHeight <= 0 ? 13 : ((tm.tmHeight + tm.tmExternalLeading + 1) / 2) * 2 - 1;
5101 case SM_SLOWMACHINE:
5102 return 0; /* Never true */
5103 case SM_MIDEASTENABLED:
5104 return 0; /* FIXME */
5105 case SM_MOUSEWHEELPRESENT:
5106 return 1;
5107 case SM_CXSCREEN:
5108 rect = get_primary_monitor_rect( get_thread_dpi() );
5109 return rect.right - rect.left;
5110 case SM_CYSCREEN:
5111 rect = get_primary_monitor_rect( get_thread_dpi() );
5112 return rect.bottom - rect.top;
5113 case SM_XVIRTUALSCREEN:
5114 rect = get_virtual_screen_rect( get_thread_dpi() );
5115 return rect.left;
5116 case SM_YVIRTUALSCREEN:
5117 rect = get_virtual_screen_rect( get_thread_dpi() );
5118 return rect.top;
5119 case SM_CXVIRTUALSCREEN:
5120 rect = get_virtual_screen_rect( get_thread_dpi() );
5121 return rect.right - rect.left;
5122 case SM_CYVIRTUALSCREEN:
5123 rect = get_virtual_screen_rect( get_thread_dpi() );
5124 return rect.bottom - rect.top;
5125 case SM_CMONITORS:
5126 if (!lock_display_devices()) return FALSE;
5127 ret = active_monitor_count();
5128 unlock_display_devices();
5129 return ret;
5130 case SM_SAMEDISPLAYFORMAT:
5131 return 1;
5132 case SM_IMMENABLED:
5133 return 0; /* FIXME */
5134 case SM_CXFOCUSBORDER:
5135 case SM_CYFOCUSBORDER:
5136 return 1;
5137 case SM_TABLETPC:
5138 case SM_MEDIACENTER:
5139 return 0;
5140 case SM_CMETRICS:
5141 return SM_CMETRICS;
5142 default:
5143 return 0;
5147 static int get_system_metrics_for_dpi( int index, unsigned int dpi )
5149 NONCLIENTMETRICSW ncm;
5150 ICONMETRICSW im;
5151 UINT ret;
5152 HDC hdc;
5154 /* some metrics are dynamic */
5155 switch (index)
5157 case SM_CXVSCROLL:
5158 case SM_CYHSCROLL:
5159 get_entry_dpi( &entry_SCROLLWIDTH, 0, &ret, dpi );
5160 return max( ret, 8 );
5161 case SM_CYCAPTION:
5162 ncm.cbSize = sizeof(ncm);
5163 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
5164 return ncm.iCaptionHeight + 1;
5165 case SM_CYVTHUMB:
5166 case SM_CXHTHUMB:
5167 case SM_CYVSCROLL:
5168 case SM_CXHSCROLL:
5169 get_entry_dpi( &entry_SCROLLHEIGHT, 0, &ret, dpi );
5170 return max( ret, 8 );
5171 case SM_CXICON:
5172 case SM_CYICON:
5173 return map_to_dpi( 32, dpi );
5174 case SM_CXCURSOR:
5175 case SM_CYCURSOR:
5176 ret = map_to_dpi( 32, dpi );
5177 if (ret >= 64) return 64;
5178 if (ret >= 48) return 48;
5179 return 32;
5180 case SM_CYMENU:
5181 ncm.cbSize = sizeof(ncm);
5182 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
5183 return ncm.iMenuHeight + 1;
5184 case SM_CXSIZE:
5185 get_entry_dpi( &entry_CAPTIONWIDTH, 0, &ret, dpi );
5186 return max( ret, 8 );
5187 case SM_CYSIZE:
5188 ncm.cbSize = sizeof(ncm);
5189 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
5190 return ncm.iCaptionHeight;
5191 case SM_CXFRAME:
5192 get_entry_dpi( &entry_BORDER, 0, &ret, dpi );
5193 ret = max( ret, 1 );
5194 return get_system_metrics_for_dpi( SM_CXDLGFRAME, dpi ) + ret;
5195 case SM_CYFRAME:
5196 get_entry_dpi( &entry_BORDER, 0, &ret, dpi );
5197 ret = max( ret, 1 );
5198 return get_system_metrics_for_dpi( SM_CYDLGFRAME, dpi ) + ret;
5199 case SM_CXICONSPACING:
5200 im.cbSize = sizeof(im);
5201 NtUserSystemParametersInfoForDpi( SPI_GETICONMETRICS, sizeof(im), &im, 0, dpi );
5202 return im.iHorzSpacing;
5203 case SM_CYICONSPACING:
5204 im.cbSize = sizeof(im);
5205 NtUserSystemParametersInfoForDpi( SPI_GETICONMETRICS, sizeof(im), &im, 0, dpi );
5206 return im.iVertSpacing;
5207 case SM_CXSMICON:
5208 case SM_CYSMICON:
5209 return map_to_dpi( 16, dpi ) & ~1;
5210 case SM_CYSMCAPTION:
5211 ncm.cbSize = sizeof(ncm);
5212 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
5213 return ncm.iSmCaptionHeight + 1;
5214 case SM_CXSMSIZE:
5215 get_entry_dpi( &entry_SMCAPTIONWIDTH, 0, &ret, dpi );
5216 return ret;
5217 case SM_CYSMSIZE:
5218 ncm.cbSize = sizeof(ncm);
5219 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
5220 return ncm.iSmCaptionHeight;
5221 case SM_CXMENUSIZE:
5222 get_entry_dpi( &entry_MENUWIDTH, 0, &ret, dpi );
5223 return ret;
5224 case SM_CYMENUSIZE:
5225 ncm.cbSize = sizeof(ncm);
5226 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
5227 return ncm.iMenuHeight;
5228 case SM_CXMENUCHECK:
5229 case SM_CYMENUCHECK:
5231 TEXTMETRICW tm;
5232 ncm.cbSize = sizeof(ncm);
5233 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
5234 hdc = get_display_dc();
5235 get_text_metr_size( hdc, &ncm.lfMenuFont, &tm, NULL);
5236 release_display_dc( hdc );
5237 return tm.tmHeight <= 0 ? 13 : ((tm.tmHeight + tm.tmExternalLeading - 1) | 1);
5239 default:
5240 return get_system_metrics( index );
5244 COLORREF get_sys_color( int index )
5246 COLORREF ret = 0;
5248 if (index >= 0 && index < ARRAY_SIZE( system_colors ))
5249 get_entry( &system_colors[index], 0, &ret );
5250 return ret;
5253 HBRUSH get_55aa_brush(void)
5255 static const WORD pattern[] = { 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa };
5256 static HBRUSH brush_55aa;
5258 if (!brush_55aa)
5260 HBITMAP bitmap = NtGdiCreateBitmap( 8, 8, 1, 1, pattern );
5261 HBRUSH brush = NtGdiCreatePatternBrushInternal( bitmap, FALSE, FALSE );
5262 NtGdiDeleteObjectApp( bitmap );
5263 make_gdi_object_system( brush, TRUE );
5264 if (InterlockedCompareExchangePointer( (void **)&brush_55aa, brush, 0 ))
5266 make_gdi_object_system( brush, FALSE );
5267 NtGdiDeleteObjectApp( brush );
5270 return brush_55aa;
5273 HBRUSH get_sys_color_brush( unsigned int index )
5275 if (index == COLOR_55AA_BRUSH) return get_55aa_brush();
5276 if (index >= ARRAY_SIZE( system_colors )) return 0;
5278 if (!system_colors[index].brush)
5280 HBRUSH brush = NtGdiCreateSolidBrush( get_sys_color( index ), NULL );
5281 make_gdi_object_system( brush, TRUE );
5282 if (InterlockedCompareExchangePointer( (void **)&system_colors[index].brush, brush, 0 ))
5284 make_gdi_object_system( brush, FALSE );
5285 NtGdiDeleteObjectApp( brush );
5288 return system_colors[index].brush;
5291 HPEN get_sys_color_pen( unsigned int index )
5293 if (index >= ARRAY_SIZE( system_colors )) return 0;
5295 if (!system_colors[index].pen)
5297 HPEN pen = NtGdiCreatePen( PS_SOLID, 1, get_sys_color( index ), NULL );
5298 make_gdi_object_system( pen, TRUE );
5299 if (InterlockedCompareExchangePointer( (void **)&system_colors[index].pen, pen, 0 ))
5301 make_gdi_object_system( pen, FALSE );
5302 NtGdiDeleteObjectApp( pen );
5305 return system_colors[index].pen;
5308 /**********************************************************************
5309 * NtUserGetDoubleClickTime (win32u.@)
5311 UINT WINAPI NtUserGetDoubleClickTime(void)
5313 UINT time = 0;
5315 get_entry( &entry_DOUBLECLICKTIME, 0, &time );
5316 if (!time) time = 500;
5317 return time;
5320 /*************************************************************************
5321 * NtUserSetSysColors (win32u.@)
5323 BOOL WINAPI NtUserSetSysColors( INT count, const INT *colors, const COLORREF *values )
5325 int i;
5327 if (IS_INTRESOURCE(colors)) return FALSE; /* stupid app passes a color instead of an array */
5329 for (i = 0; i < count; i++)
5330 if (colors[i] >= 0 && colors[i] <= ARRAY_SIZE( system_colors ))
5331 set_entry( &system_colors[colors[i]], values[i], 0, 0 );
5333 /* Send WM_SYSCOLORCHANGE message to all windows */
5334 send_message_timeout( HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0,
5335 SMTO_ABORTIFHUNG, 2000, FALSE );
5336 /* Repaint affected portions of all visible windows */
5337 NtUserRedrawWindow( 0, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN );
5338 return TRUE;
5342 static LONG dpi_awareness;
5344 /***********************************************************************
5345 * NtUserSetProcessDpiAwarenessContext (win32u.@)
5347 BOOL WINAPI NtUserSetProcessDpiAwarenessContext( ULONG awareness, ULONG unknown )
5349 switch (awareness)
5351 case NTUSER_DPI_UNAWARE:
5352 case NTUSER_DPI_SYSTEM_AWARE:
5353 case NTUSER_DPI_PER_MONITOR_AWARE:
5354 case NTUSER_DPI_PER_MONITOR_AWARE_V2:
5355 case NTUSER_DPI_PER_UNAWARE_GDISCALED:
5356 break;
5357 default:
5358 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
5359 return FALSE;
5362 return !InterlockedCompareExchange( &dpi_awareness, awareness, 0 );
5365 /***********************************************************************
5366 * NtUserGetProcessDpiAwarenessContext (win32u.@)
5368 ULONG WINAPI NtUserGetProcessDpiAwarenessContext( HANDLE process )
5370 DPI_AWARENESS val;
5372 if (process && process != GetCurrentProcess())
5374 WARN( "not supported on other process %p\n", process );
5375 return NTUSER_DPI_UNAWARE;
5378 val = ReadNoFence( &dpi_awareness );
5379 if (!val) return NTUSER_DPI_UNAWARE;
5380 return val;
5383 BOOL message_beep( UINT i )
5385 BOOL active = TRUE;
5386 NtUserSystemParametersInfo( SPI_GETBEEP, 0, &active, FALSE );
5387 if (active) user_driver->pBeep();
5388 return TRUE;
5391 static DWORD exiting_thread_id;
5393 /**********************************************************************
5394 * is_exiting_thread
5396 BOOL is_exiting_thread( DWORD tid )
5398 return tid == exiting_thread_id;
5401 static void thread_detach(void)
5403 struct user_thread_info *thread_info = get_user_thread_info();
5405 user_driver->pThreadDetach();
5407 free( thread_info->key_state );
5408 thread_info->key_state = 0;
5409 free( thread_info->rawinput );
5411 destroy_thread_windows();
5412 cleanup_imm_thread();
5413 NtClose( thread_info->server_queue );
5415 exiting_thread_id = 0;
5418 /***********************************************************************
5419 * NtUserCallNoParam (win32u.@)
5421 ULONG_PTR WINAPI NtUserCallNoParam( ULONG code )
5423 switch(code)
5425 case NtUserCallNoParam_DestroyCaret:
5426 return destroy_caret();
5428 case NtUserCallNoParam_GetDesktopWindow:
5429 return HandleToUlong( get_desktop_window() );
5431 case NtUserCallNoParam_GetDialogBaseUnits:
5432 return get_dialog_base_units();
5434 case NtUserCallNoParam_GetInputState:
5435 return get_input_state();
5437 case NtUserCallNoParam_GetProcessDefaultLayout:
5438 return process_layout;
5440 case NtUserCallNoParam_GetShellWindow:
5441 return HandleToUlong( get_shell_window() );
5443 case NtUserCallNoParam_ReleaseCapture:
5444 return release_capture();
5446 /* temporary exports */
5447 case NtUserExitingThread:
5448 exiting_thread_id = GetCurrentThreadId();
5449 return 0;
5451 case NtUserThreadDetach:
5452 thread_detach();
5453 return 0;
5455 default:
5456 FIXME( "invalid code %u\n", (int)code );
5457 return 0;
5461 /***********************************************************************
5462 * NtUserCallOneParam (win32u.@)
5464 ULONG_PTR WINAPI NtUserCallOneParam( ULONG_PTR arg, ULONG code )
5466 switch(code)
5468 case NtUserCallOneParam_BeginDeferWindowPos:
5469 return HandleToUlong( begin_defer_window_pos( arg ));
5471 case NtUserCallOneParam_CreateCursorIcon:
5472 return HandleToUlong( alloc_cursoricon_handle( arg ));
5474 case NtUserCallOneParam_CreateMenu:
5475 return HandleToUlong( create_menu( arg ) );
5477 case NtUserCallOneParam_EnableDC:
5478 return set_dce_flags( UlongToHandle(arg), DCHF_ENABLEDC );
5480 case NtUserCallOneParam_EnableThunkLock:
5481 enable_thunk_lock = arg;
5482 return 0;
5484 case NtUserCallOneParam_EnumClipboardFormats:
5485 return enum_clipboard_formats( arg );
5487 case NtUserCallOneParam_GetClipCursor:
5488 return get_clip_cursor( (RECT *)arg );
5490 case NtUserCallOneParam_GetCursorPos:
5491 return get_cursor_pos( (POINT *)arg );
5493 case NtUserCallOneParam_GetIconParam:
5494 return get_icon_param( UlongToHandle(arg) );
5496 case NtUserCallOneParam_GetMenuItemCount:
5497 return get_menu_item_count( UlongToHandle(arg) );
5499 case NtUserCallOneParam_GetSysColor:
5500 return get_sys_color( arg );
5502 case NtUserCallOneParam_IsWindowRectFullScreen:
5503 return is_window_rect_full_screen( (const RECT *)arg );
5505 case NtUserCallOneParam_RealizePalette:
5506 return realize_palette( UlongToHandle(arg) );
5508 case NtUserCallOneParam_GetPrimaryMonitorRect:
5509 *(RECT *)arg = get_primary_monitor_rect( 0 );
5510 return 1;
5512 case NtUserCallOneParam_GetSysColorBrush:
5513 return HandleToUlong( get_sys_color_brush(arg) );
5515 case NtUserCallOneParam_GetSysColorPen:
5516 return HandleToUlong( get_sys_color_pen(arg) );
5518 case NtUserCallOneParam_GetSystemMetrics:
5519 return get_system_metrics( arg );
5521 case NtUserCallOneParam_GetVirtualScreenRect:
5522 *(RECT *)arg = get_virtual_screen_rect( 0 );
5523 return 1;
5525 case NtUserCallOneParam_MessageBeep:
5526 return message_beep( arg );
5528 case NtUserCallOneParam_ReplyMessage:
5529 return reply_message_result( arg );
5531 case NtUserCallOneParam_SetCaretBlinkTime:
5532 return set_caret_blink_time( arg );
5534 case NtUserCallOneParam_SetProcessDefaultLayout:
5535 process_layout = arg;
5536 return TRUE;
5538 /* temporary exports */
5539 case NtUserGetDeskPattern:
5540 return get_entry( &entry_DESKPATTERN, 256, (WCHAR *)arg );
5542 default:
5543 FIXME( "invalid code %u\n", (int)code );
5544 return 0;
5548 /***********************************************************************
5549 * NtUserCallTwoParam (win32u.@)
5551 ULONG_PTR WINAPI NtUserCallTwoParam( ULONG_PTR arg1, ULONG_PTR arg2, ULONG code )
5553 switch(code)
5555 case NtUserCallTwoParam_GetDialogProc:
5556 return (ULONG_PTR)get_dialog_proc( (DLGPROC)arg1, arg2 );
5558 case NtUserCallTwoParam_GetMenuInfo:
5559 return get_menu_info( UlongToHandle(arg1), (MENUINFO *)arg2 );
5561 case NtUserCallTwoParam_GetMonitorInfo:
5562 return get_monitor_info( UlongToHandle(arg1), (MONITORINFO *)arg2 );
5564 case NtUserCallTwoParam_GetSystemMetricsForDpi:
5565 return get_system_metrics_for_dpi( arg1, arg2 );
5567 case NtUserCallTwoParam_MonitorFromRect:
5568 return HandleToUlong( monitor_from_rect( (const RECT *)arg1, arg2, get_thread_dpi() ));
5570 case NtUserCallTwoParam_SetCaretPos:
5571 return set_caret_pos( arg1, arg2 );
5573 case NtUserCallTwoParam_SetIconParam:
5574 return set_icon_param( UlongToHandle(arg1), arg2 );
5576 case NtUserCallTwoParam_UnhookWindowsHook:
5577 return unhook_windows_hook( arg1, (HOOKPROC)arg2 );
5579 /* temporary exports */
5580 case NtUserAllocWinProc:
5581 return (UINT_PTR)alloc_winproc( (WNDPROC)arg1, arg2 );
5583 default:
5584 FIXME( "invalid code %u\n", (int)code );
5585 return 0;
5589 /***********************************************************************
5590 * NtUserDisplayConfigGetDeviceInfo (win32u.@)
5592 NTSTATUS WINAPI NtUserDisplayConfigGetDeviceInfo( DISPLAYCONFIG_DEVICE_INFO_HEADER *packet )
5594 NTSTATUS ret = STATUS_UNSUCCESSFUL;
5596 TRACE( "packet %p.\n", packet );
5598 if (!packet || packet->size < sizeof(*packet))
5599 return STATUS_UNSUCCESSFUL;
5601 switch (packet->type)
5603 case DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME:
5605 DISPLAYCONFIG_SOURCE_DEVICE_NAME *source_name = (DISPLAYCONFIG_SOURCE_DEVICE_NAME *)packet;
5606 struct adapter *adapter;
5608 TRACE( "DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME.\n" );
5610 if (packet->size < sizeof(*source_name))
5611 return STATUS_INVALID_PARAMETER;
5613 if (!lock_display_devices()) return STATUS_UNSUCCESSFUL;
5615 LIST_FOR_EACH_ENTRY(adapter, &adapters, struct adapter, entry)
5617 if (source_name->header.id != adapter->id) continue;
5618 if (memcmp( &source_name->header.adapterId, &adapter->gpu_luid, sizeof(adapter->gpu_luid) )) continue;
5620 lstrcpyW( source_name->viewGdiDeviceName, adapter->dev.device_name );
5621 ret = STATUS_SUCCESS;
5622 break;
5625 unlock_display_devices();
5626 return ret;
5628 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME:
5630 DISPLAYCONFIG_TARGET_DEVICE_NAME *target_name = (DISPLAYCONFIG_TARGET_DEVICE_NAME *)packet;
5631 char buffer[ARRAY_SIZE(target_name->monitorFriendlyDeviceName)];
5632 struct monitor *monitor;
5634 TRACE( "DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME.\n" );
5636 if (packet->size < sizeof(*target_name))
5637 return STATUS_INVALID_PARAMETER;
5639 if (!lock_display_devices()) return STATUS_UNSUCCESSFUL;
5641 memset( &target_name->flags, 0, sizeof(*target_name) - offsetof(DISPLAYCONFIG_TARGET_DEVICE_NAME, flags) );
5643 LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry)
5645 if (target_name->header.id != monitor->output_id) continue;
5646 if (memcmp( &target_name->header.adapterId, &monitor->adapter->gpu_luid,
5647 sizeof(monitor->adapter->gpu_luid) ))
5648 continue;
5650 target_name->outputTechnology = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL;
5651 /* FIXME: get real monitor name. */
5652 snprintf( buffer, ARRAY_SIZE(buffer), "Display%u", monitor->output_id + 1 );
5653 asciiz_to_unicode( target_name->monitorFriendlyDeviceName, buffer );
5654 lstrcpyW( target_name->monitorDevicePath, monitor->dev.interface_name );
5655 ret = STATUS_SUCCESS;
5656 break;
5659 unlock_display_devices();
5660 return ret;
5662 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE:
5664 DISPLAYCONFIG_TARGET_PREFERRED_MODE *preferred_mode = (DISPLAYCONFIG_TARGET_PREFERRED_MODE *)packet;
5666 FIXME( "DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE stub.\n" );
5668 if (packet->size < sizeof(*preferred_mode))
5669 return STATUS_INVALID_PARAMETER;
5671 return STATUS_NOT_SUPPORTED;
5673 case DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME:
5675 DISPLAYCONFIG_ADAPTER_NAME *adapter_name = (DISPLAYCONFIG_ADAPTER_NAME *)packet;
5677 FIXME( "DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME stub.\n" );
5679 if (packet->size < sizeof(*adapter_name))
5680 return STATUS_INVALID_PARAMETER;
5682 return STATUS_NOT_SUPPORTED;
5684 case DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE:
5685 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE:
5686 case DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION:
5687 case DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION:
5688 case DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO:
5689 case DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE:
5690 case DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL:
5691 default:
5692 FIXME( "Unimplemented packet type %u.\n", packet->type );
5693 return STATUS_INVALID_PARAMETER;