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
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',
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','}',
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','}',
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','}',
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','}',
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','}',
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','}',
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','}',
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','}',
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','}',
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 */
213 struct display_device dev
;
216 const WCHAR
*config_key
;
217 unsigned int mode_count
;
224 struct display_device dev
;
225 struct adapter
*adapter
;
229 unsigned int output_id
;
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 */
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
;
296 enum parameter_key mirror_key
;
301 struct sysparam_uint_entry
303 struct sysparam_entry hdr
;
307 struct sysparam_bool_entry
309 struct sysparam_entry hdr
;
313 struct sysparam_dword_entry
315 struct sysparam_entry hdr
;
319 struct sysparam_rgb_entry
321 struct sysparam_entry hdr
;
327 struct sysparam_binary_entry
329 struct sysparam_entry hdr
;
334 struct sysparam_path_entry
336 struct sysparam_entry hdr
;
340 struct sysparam_font_entry
342 struct sysparam_entry hdr
;
345 WCHAR fullname
[LF_FACESIZE
];
348 struct sysparam_pref_entry
350 struct sysparam_entry hdr
;
351 union sysparam_all_entry
*parent
;
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
;
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" );
400 static HANDLE
get_display_device_init_mutex( void )
403 UNICODE_STRING name
= {.Buffer
= bufferW
};
404 OBJECT_ATTRIBUTES attr
;
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
);
418 static void release_display_device_init_mutex( HANDLE mutex
)
420 NtReleaseMutant( mutex
, NULL
);
424 static struct adapter
*adapter_acquire( struct adapter
*adapter
)
426 InterlockedIncrement( &adapter
->refcount
);
430 static void adapter_release( struct adapter
*adapter
)
432 if (!InterlockedDecrement( &adapter
->refcount
))
434 free( adapter
->modes
);
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
) );
466 static BOOL
adapter_get_registry_settings( const struct adapter
*adapter
, DEVMODEW
*mode
)
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
;
478 ret
= read_adapter_mode( hkey
, ENUM_REGISTRY_SETTINGS
, mode
);
482 release_display_device_init_mutex( mutex
);
486 static BOOL
adapter_set_registry_settings( const struct adapter
*adapter
, const DEVMODEW
*mode
)
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
;
498 ret
= write_adapter_mode( hkey
, ENUM_REGISTRY_SETTINGS
, mode
);
502 release_display_device_init_mutex( mutex
);
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
);
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
;
523 ret
= read_adapter_mode( hkey
, ENUM_CURRENT_SETTINGS
, mode
);
527 release_display_device_init_mutex( mutex
);
531 static BOOL
adapter_set_current_settings( const struct adapter
*adapter
, const DEVMODEW
*mode
)
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
;
543 ret
= write_adapter_mode( hkey
, ENUM_CURRENT_SETTINGS
, mode
);
547 release_display_device_init_mutex( mutex
);
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
;
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
;
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
;
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
;
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
)
620 if (!(subkey
= reg_open_key( hkey
, name
, name_size
))) return 0;
621 size
= query_reg_value( subkey
, NULL
, value
, size
);
626 static BOOL
read_display_adapter_settings( unsigned int index
, struct adapter
*info
)
629 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
630 WCHAR
*value_str
= (WCHAR
*)value
->Data
;
635 if (!enum_key
&& !(enum_key
= reg_open_key( NULL
, enum_keyW
, sizeof(enum_keyW
) )))
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
))
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
) )))
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
);
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
) )))
666 if (query_reg_value( hkey
, state_flagsW
, value
, sizeof(buffer
) ) && value
->Type
== REG_DWORD
)
667 info
->dev
.state_flags
= *(const DWORD
*)value
->Data
;
670 info
->dev
.interface_name
[0] = 0;
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
);
691 size
= query_reg_value( hkey
, gpu_idW
, value
, sizeof(buffer
) );
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
) )))
698 size
= query_reg_subkey_value( hkey
, devpropkey_gpu_luidW
, sizeof(devpropkey_gpu_luidW
), value
, sizeof(buffer
) );
699 if (size
!= sizeof(info
->gpu_luid
))
704 memcpy( &info
->gpu_luid
, value
->Data
, sizeof(info
->gpu_luid
) );
706 size
= query_reg_value( hkey
, hardware_idW
, value
, sizeof(buffer
) );
708 if (!size
|| (value
->Type
!= REG_SZ
&& value
->Type
!= REG_MULTI_SZ
))
711 lstrcpyW( info
->dev
.device_id
, value_str
);
715 static BOOL
read_monitor_settings( struct adapter
*adapter
, UINT index
, struct monitor
*monitor
)
718 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
719 WCHAR
*device_name
, *value_str
= (WCHAR
*)value
->Data
, *ptr
;
723 monitor
->flags
= adapter
->id
? 0 : MONITORINFOF_PRIMARY
;
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
) )))
734 sprintf( buffer
, "MonitorID%u", index
);
735 size
= query_reg_ascii_value( hkey
, buffer
, value
, sizeof(buffer
) );
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
) )))
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
))
761 monitor
->dev
.state_flags
= *(const DWORD
*)value
->Data
;
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
))
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
))
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
))
794 monitor
->rc_work
= *(const RECT
*)value
->Data
;
797 if (!query_reg_value( hkey
, device_descW
, value
, sizeof(buffer
) ) || value
->Type
!= REG_SZ
)
802 memcpy( monitor
->dev
.device_string
, value
->Data
, value
->DataLength
);
805 if (!query_reg_value( hkey
, driverW
, value
, sizeof(buffer
) ) || value
->Type
!= REG_SZ
)
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
);
816 if (!query_reg_value( hkey
, hardware_idW
, value
, sizeof(buffer
) ) ||
817 (value
->Type
!= REG_SZ
&& value
->Type
!= REG_MULTI_SZ
))
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
);
831 static void reg_empty_key( HKEY root
, const char *key_name
)
834 KEY_NODE_INFORMATION
*key
= (KEY_NODE_INFORMATION
*)buffer
;
835 KEY_VALUE_FULL_INFORMATION
*value
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
841 hkey
= reg_open_key( root
, bufferW
, asciiz_to_unicode( bufferW
, key_name
) - sizeof(WCHAR
) );
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)
860 KEY_NODE_INFORMATION
*key
= (void *)buffer
;
861 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
862 WCHAR
*value_str
= (WCHAR
*)value
->Data
;
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
),
878 reg_empty_key( hkey
, NULL
);
879 set_reg_value( hkey
, classW
, REG_SZ
, monitorW
, sizeof(monitorW
) );
882 /* delete adapters */
883 reg_empty_key( video_key
, NULL
);
886 sprintf( buffer
, "Class\\%s", guid_devclass_displayA
);
887 hkey
= reg_create_key( control_key
, bufferW
, asciiz_to_unicode( bufferW
, buffer
) - sizeof(WCHAR
),
889 reg_empty_key( hkey
, NULL
);
890 set_reg_value( hkey
, classW
, REG_SZ
, displayW
, sizeof(displayW
) );
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
))
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
);
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
) );
924 NtClose( device_key
);
933 static void cleanup_devices(void)
936 KEY_NODE_INFORMATION
*key
= (void *)buffer
;
937 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
938 WCHAR bufferW
[512], *value_str
= (WCHAR
*)value
->Data
;
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
))
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
);
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
;
974 NtClose( device_key
);
976 if (!present
&& reg_delete_tree( subkey
, bufferW
, lstrlenW( bufferW
) * sizeof(WCHAR
) ))
987 static void uuid_create( GUID
*uuid
)
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
;
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;
1020 year
= years
+ 1524;
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
;
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
;
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
) );
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
) );
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
);
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
) );
1092 static void add_gpu( const struct gdi_gpu
*gpu
, void *param
)
1094 struct device_manager_ctx
*ctx
= param
;
1098 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
1099 unsigned int gpu_index
, size
;
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
)))
1137 ctx
->mutex
= get_display_device_init_mutex();
1138 pthread_mutex_lock( &display_lock
);
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
) );
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
) ))
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
);
1178 memcpy( ctx
->gpu_guid
, value
->Data
, value
->DataLength
);
1179 TRACE( "got guid %s\n", debugstr_w(ctx
->gpu_guid
) );
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
) );
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
) );
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
) );
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
);
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
) );
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
];
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
) );
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
);
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
];
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
),
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
);
1348 set_reg_value( subkey
, bad_edidW
, REG_BINARY
, NULL
, 0 );
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
) );
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
) );
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
) );
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
));
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
) );
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
) );
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
))
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
=
1445 static void release_display_manager_ctx( struct device_manager_ctx
*ctx
)
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
);
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
);
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
;
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
) )))
1502 status
= NtQueryKey( video_key
, KeyBasicInformation
, &key
,
1503 offsetof(KEY_BASIC_INFORMATION
, Name
), &size
);
1504 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
)
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
);
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
))
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
;
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
);
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
);
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}};
1609 add_gpu( &gpu
, &ctx
);
1610 add_adapter( &adapter
, &ctx
);
1612 if (!read_adapter_mode( ctx
.adapter_key
, ENUM_CURRENT_SETTINGS
, &mode
))
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())
1632 ERR( "Failed to read display config.\n" );
1638 ERR( "Driver reported devices, but we failed to read them.\n" );
1642 return update_display_cache( TRUE
);
1648 static BOOL
lock_display_devices(void)
1650 if (!update_display_cache( FALSE
)) return FALSE
;
1651 pthread_mutex_lock( &display_lock
);
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
);
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
);
1671 NtGdiDeleteObjectApp( dc
);
1678 static void release_display_dc( HDC hdc
)
1680 pthread_mutex_unlock( &display_dc_lock
);
1683 /**********************************************************************
1686 UINT
get_monitor_dpi( HMONITOR monitor
)
1688 /* FIXME: use the monitor DPI instead */
1692 /**********************************************************************
1693 * get_win_monitor_dpi
1695 UINT
get_win_monitor_dpi( HWND hwnd
)
1697 /* FIXME: use the monitor DPI instead */
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
);
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
:
1725 return DPI_AWARENESS_INVALID
;
1729 DWORD
get_process_layout(void)
1731 return process_layout
== ~0u ? 0 : process_layout
;
1734 /**********************************************************************
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
;
1754 /* see GetAwarenessFromDpiAwarenessContext */
1755 static DPI_AWARENESS
get_awareness_from_dpi_awareness_context( DPI_AWARENESS_CONTEXT context
)
1757 switch ((ULONG_PTR
)context
)
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
;
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
);
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 /**********************************************************************
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
);
1813 /**********************************************************************
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
);
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
;
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
);
1893 static BOOL
is_window_rect_full_screen( const RECT
*rect
)
1895 struct monitor
*monitor
;
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
))
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
)
1913 unlock_display_devices();
1917 RECT
get_display_rect( const WCHAR
*display
)
1919 struct monitor
*monitor
;
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
;
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
;
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
;
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
;
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
;
1972 case QDC_ONLY_ACTIVE_PATHS
:
1973 case QDC_DATABASE_CURRENT
:
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
))
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
);
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
);
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
) );
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();
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
);
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 ); \
2101 static const char *_CDS_flags( DWORD fields
)
2107 _X_FIELD(CDS
, UPDATEREGISTRY
)
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
)
2120 return wine_dbg_sprintf( "%s", buf
);
2123 static const char *_DM_fields( DWORD fields
)
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
)
2138 return wine_dbg_sprintf( "%s", buf
);
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
);
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
))
2182 if ((devmode
->dmFields
& DM_BITSPERPEL
) && devmode
->dmBitsPerPel
&& devmode
->dmBitsPerPel
!= mode
->dmBitsPerPel
)
2184 if ((devmode
->dmFields
& DM_PELSWIDTH
) && devmode
->dmPelsWidth
!= mode
->dmPelsWidth
)
2186 if ((devmode
->dmFields
& DM_PELSHEIGHT
) && devmode
->dmPelsHeight
!= mode
->dmPelsHeight
)
2188 if ((devmode
->dmFields
& DM_DISPLAYFREQUENCY
) && devmode
->dmDisplayFrequency
!= mode
->dmDisplayFrequency
2189 && devmode
->dmDisplayFrequency
> 1 && mode
->dmDisplayFrequency
)
2191 if ((devmode
->dmFields
& DM_DISPLAYORIENTATION
) && devmode
->dmDisplayOrientation
!= mode
->dmDisplayOrientation
)
2193 if ((devmode
->dmFields
& DM_DISPLAYFLAGS
) && (mode
->dmFields
& DM_DISPLAYFLAGS
) &&
2194 (devmode
->dmDisplayFlags
& DM_INTERLACED
) != (mode
->dmDisplayFlags
& DM_INTERLACED
))
2196 if ((devmode
->dmFields
& DM_DISPLAYFIXEDOUTPUT
) && (mode
->dmFields
& DM_DISPLAYFIXEDOUTPUT
) &&
2197 devmode
->dmDisplayFixedOutput
!= mode
->dmDisplayFixedOutput
)
2206 static BOOL
adapter_get_full_mode( const struct adapter
*adapter
, const DEVMODEW
*devmode
, DEVMODEW
*full_mode
)
2208 const DEVMODEW
*adapter_mode
;
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
))
2223 if (devmode
) memcpy( full_mode
, devmode
, devmode
->dmSize
);
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
);
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
, ¤t_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
;
2267 /* allocate an extra mode for easier iteration */
2268 if (!(displays
= calloc( list_count( &adapters
) + 1, sizeof(DEVMODEW
) ))) return NULL
;
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
) );
2278 if (!devname
) ret
= adapter_get_registry_settings( adapter
, mode
);
2279 else ret
= adapter_get_current_settings( adapter
, mode
);
2287 lstrcpyW( mode
->dmDeviceName
, adapter
->dev
.device_name
);
2288 mode
= NEXT_DEVMODEW(mode
);
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
;
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
;
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
;
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
))
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
;
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
)
2393 /* Move the bottom right vertex to the point */
2395 left_top
.x
= points
[point_idx
].x
- width
;
2396 left_top
.y
= points
[point_idx
].y
- height
;
2398 /* Move the bottom left vertex to the point */
2400 left_top
.x
= points
[point_idx
].x
;
2401 left_top
.y
= points
[point_idx
].y
- height
;
2403 /* Move the top right vertex to the point */
2405 left_top
.x
= points
[point_idx
].x
- width
;
2406 left_top
.y
= points
[point_idx
].y
;
2408 /* Move the top left vertex to the point */
2410 left_top
.x
= points
[point_idx
].x
;
2411 left_top
.y
= points
[point_idx
].y
;
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
))
2423 min_offset
= offset
;
2428 if (offset_length( offset
) < offset_length( min_offset
)) min_offset
= 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 */
2448 /* Place the unplaced display with the minimum offset length first */
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
;
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
;
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
;
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" );
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. */
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();
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
, ¤t_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
);
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
);
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
, ¤t_mode
))
2581 WARN( "Failed to query current display mode for EDS_ROTATEDMODE flag.\n" );
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
)
2590 if (!(flags
& EDS_RAWMODE
) && (adapter_mode
->dmFields
& DM_DISPLAYFLAGS
) &&
2591 (adapter_mode
->dmDisplayFlags
& WINE_DM_UNSUPPORTED
))
2595 memcpy( &devmode
->dmFields
, &adapter_mode
->dmFields
, devmode
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmFields
) );
2596 devmode
->dmDisplayFlags
&= ~WINE_DM_UNSUPPORTED
;
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
);
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
;
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
);
2640 struct monitor_enum_info
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
++;
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
;
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
;
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();
2699 LIST_FOR_EACH_ENTRY(monitor
, &monitors
, struct monitor
, entry
)
2703 if (!(monitor
->dev
.state_flags
& DISPLAY_DEVICE_ACTIVE
)) continue;
2705 monrect
= map_dpi_rect( monitor
->rc_monitor
, get_monitor_dpi( monitor
->handle
),
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
;
2716 unlock_display_devices();
2720 params
.lparam
= lparam
;
2721 for (i
= 0; i
< count
; i
++)
2725 params
.monitor
= enum_info
[i
].handle
;
2726 params
.rect
= enum_info
[i
].rect
;
2727 if (!KeUserModeCallback( NtUserCallEnumDisplayMonitor
, ¶ms
, sizeof(params
),
2728 &ret_ptr
, &ret_len
))
2734 if (enum_info
!= enum_buf
) free( enum_info
);
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
);
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
));
2776 unlock_display_devices();
2777 WARN( "invalid handle %p\n", handle
);
2778 RtlSetLastWin32Error( ERROR_INVALID_MONITOR_HANDLE
);
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
;
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
)
2801 RECT monitor_rect
= map_dpi_rect( monitor
->rc_monitor
, get_monitor_dpi( monitor
->handle
),
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
)
2811 ret
= monitor
->handle
;
2814 else if (!max_area
) /* if not intersecting, check for min distance */
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
;
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
;
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();
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
);
2848 HMONITOR
monitor_from_point( POINT pt
, UINT flags
, UINT dpi
)
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
)
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
);
2890 /***********************************************************************
2891 * NtUserGetDpiForMonitor (win32u.@)
2893 BOOL WINAPI
NtUserGetDpiForMonitor( HMONITOR monitor
, UINT type
, UINT
*x
, UINT
*y
)
2897 RtlSetLastWin32Error( ERROR_BAD_ARGUMENTS
);
2902 RtlSetLastWin32Error( ERROR_INVALID_ADDRESS
);
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;
2914 /**********************************************************************
2915 * LogicalToPhysicalPointForPerMonitorDPI (win32u.@)
2917 BOOL WINAPI
NtUserLogicalToPerMonitorDPIPhysicalPoint( HWND hwnd
, POINT
*pt
)
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
);
2927 /**********************************************************************
2928 * NtUserPerMonitorDPIPhysicalToLogicalPoint (win32u.@)
2930 BOOL WINAPI
NtUserPerMonitorDPIPhysicalToLogicalPoint( HWND hwnd
, POINT
*pt
)
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
);
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
];
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
),
2958 if (InterlockedCompareExchangePointer( (void **)&base_keys
[index
], key
, 0 ))
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
)))
2967 if (InterlockedCompareExchangePointer( (void **)&volatile_keys
[index
], key
, 0 ))
2970 if (base_key
) *base_key
= base_keys
[index
];
2971 if (volatile_key
) *volatile_key
= volatile_keys
[index
];
2975 /* load a value to a registry entry */
2976 static DWORD
load_entry( struct sysparam_entry
*entry
, void *data
, DWORD size
)
2979 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
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
) );
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
;
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
;
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
);
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
;
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
;
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
;
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
)
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
;
3081 /* initialize an int parameter */
3082 static BOOL
init_int_entry( union sysparam_all_entry
*entry
)
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
)
3100 if (load_entry( &entry
->hdr
, buf
, sizeof(buf
) )) entry
->uint
.val
= wcstol( buf
, NULL
, 10 );
3102 *(UINT
*)ptr_param
= entry
->uint
.val
;
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
)
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
;
3120 /* initialize a uint parameter */
3121 static BOOL
init_uint_entry( union sysparam_all_entry
*entry
)
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
)
3136 if (!ptr_param
) return FALSE
;
3138 if (!entry
->hdr
.loaded
)
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.
3147 * Technical Reference to the Windows 2000 Registry ->
3148 * HKEY_CURRENT_USER -> Control Panel -> Desktop -> WindowMetrics
3150 val
= entry
->uint
.val
;
3152 val
= muldiv( -val
, dpi
, 1440 );
3154 val
= map_to_dpi( val
, dpi
);
3156 *(int *)ptr_param
= val
;
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
)
3176 if (load_entry( &entry
->hdr
, buf
, sizeof(buf
) )) entry
->bool.val
= wcstol( buf
, NULL
, 10 ) != 0;
3178 *(UINT
*)ptr_param
= entry
->bool.val
;
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
;
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
)
3209 if (load_entry( &entry
->hdr
, buf
, sizeof(buf
) )) entry
->bool.val
= !wcsicmp( yesW
, buf
);
3211 *(UINT
*)ptr_param
= entry
->bool.val
;
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
;
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
)
3240 if (load_entry( &entry
->hdr
, &val
, sizeof(val
) ) == sizeof(DWORD
)) entry
->dword
.val
= val
;
3242 *(DWORD
*)ptr_param
= entry
->dword
.val
;
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
;
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
)
3272 if (load_entry( &entry
->hdr
, buf
, sizeof(buf
) ))
3275 WCHAR
*end
, *str
= buf
;
3277 r
= wcstoul( str
, &end
, 10 );
3278 if (end
== str
|| !*end
) goto done
;
3280 g
= wcstoul( str
, &end
, 10 );
3281 if (end
== str
|| !*end
) goto done
;
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
);
3290 *(COLORREF
*)ptr_param
= entry
->rgb
.val
;
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
)
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
);
3320 /* initialize an RGB parameter */
3321 static BOOL
init_rgb_entry( union sysparam_all_entry
*entry
)
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
);
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
];
3354 lstrcpynW( buffer
, ptr_param
, MAX_PATH
);
3355 ret
= save_entry_string( &entry
->hdr
, buffer
, flags
);
3358 lstrcpyW( entry
->path
.path
, buffer
);
3359 entry
->hdr
.loaded
= TRUE
;
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
);
3382 memcpy( entry
->bin
.ptr
, buffer
, entry
->bin
.size
);
3383 memset( (char *)entry
->bin
.ptr
+ len
, 0, entry
->bin
.size
- len
);
3387 memcpy( ptr_param
, entry
->bin
.ptr
, min( int_param
, entry
->bin
.size
) );
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
)
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
);
3402 memcpy( entry
->bin
.ptr
, buffer
, entry
->bin
.size
);
3403 entry
->hdr
.loaded
= TRUE
;
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
);
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
);
3447 lstrcpyW( fullname
, enum_entry
.lf
.elfFullName
);
3449 lstrcpyW( fullname
, lf
->lfFaceName
);
3452 LONG
get_char_dimensions( HDC hdc
, TEXTMETRICW
*metric
, int *height
)
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 ))
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
;
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;
3482 if (hfont
) NtGdiDeleteObjectApp( hfont
);
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)
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
)
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
)
3537 if (!ptr_param
) return FALSE
;
3539 if (!entry
->hdr
.loaded
)
3541 switch (load_entry( &entry
->hdr
, &font
, 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
;
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 );
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
));
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
;
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
;
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
)
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
;
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
;
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;
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
;
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 */
3799 SPI_SETWORKAREA_IDX
,
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" )
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
;
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
) );
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");
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");
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
;
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
;
3986 /***********************************************************************
3987 * NtUserSystemParametersInfoForDpi (win32u.@)
3989 BOOL WINAPI
NtUserSystemParametersInfoForDpi( UINT action
, UINT val
, PVOID ptr
, UINT winini
, UINT dpi
)
3995 case SPI_GETICONTITLELOGFONT
:
3996 ret
= get_entry_dpi( &entry_ICONTITLELOGFONT
, val
, ptr
, dpi
);
3998 case SPI_GETNONCLIENTMETRICS
:
4000 NONCLIENTMETRICSW
*ncm
= ptr
;
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
);
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
);
4033 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
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
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) \
4068 static BOOL warn = TRUE; \
4072 FIXME( "Unimplemented action: %u (%s)\n", x, #x ); \
4075 RtlSetLastWin32Error( ERROR_INVALID_SPI_VALUE ); \
4078 #define WINE_SPI_WARN(x) \
4080 WARN( "Ignored action: %u (%s)\n", x, #x ); \
4084 BOOL ret
= user_driver
->pSystemParametersInfo( action
, val
, ptr
, winini
);
4085 unsigned spi_idx
= 0;
4087 if (!ret
) switch (action
)
4090 ret
= get_entry( &entry_BEEP
, val
, ptr
);
4093 ret
= set_entry( &entry_BEEP
, val
, ptr
, winini
);
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 );
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
);
4106 ret
= get_entry( &entry_BORDER
, val
, ptr
);
4107 if (*(INT
*)ptr
< 1) *(INT
*)ptr
= 1;
4110 ret
= set_entry( &entry_BORDER
, val
, ptr
, winini
);
4112 case SPI_GETKEYBOARDSPEED
:
4113 ret
= get_entry( &entry_KEYBOARDSPEED
, val
, ptr
);
4115 case SPI_SETKEYBOARDSPEED
:
4116 if (val
> 31) val
= 31;
4117 ret
= set_entry( &entry_KEYBOARDSPEED
, val
, ptr
, winini
);
4120 WINE_SPI_WARN(SPI_LANGDRIVER
); /* not implemented in Windows */
4122 case SPI_ICONHORIZONTALSPACING
:
4124 ret
= get_entry( &entry_ICONHORIZONTALSPACING
, val
, ptr
);
4127 int min_val
= map_to_dpi( 32, get_system_dpi() );
4128 ret
= set_entry( &entry_ICONHORIZONTALSPACING
, max( min_val
, val
), ptr
, winini
);
4131 case SPI_GETSCREENSAVETIMEOUT
:
4132 ret
= get_entry( &entry_SCREENSAVETIMEOUT
, val
, ptr
);
4134 case SPI_SETSCREENSAVETIMEOUT
:
4135 ret
= set_entry( &entry_SCREENSAVETIMEOUT
, val
, ptr
, winini
);
4137 case SPI_GETSCREENSAVEACTIVE
:
4138 ret
= get_entry( &entry_SCREENSAVEACTIVE
, val
, ptr
);
4140 case SPI_SETSCREENSAVEACTIVE
:
4141 ret
= set_entry( &entry_SCREENSAVEACTIVE
, val
, ptr
, winini
);
4143 case SPI_GETGRIDGRANULARITY
:
4144 ret
= get_entry( &entry_GRIDGRANULARITY
, val
, ptr
);
4146 case SPI_SETGRIDGRANULARITY
:
4147 ret
= set_entry( &entry_GRIDGRANULARITY
, val
, ptr
, winini
);
4149 case SPI_SETDESKWALLPAPER
:
4150 if (!ptr
|| set_entry( &entry_DESKWALLPAPER
, val
, ptr
, winini
))
4151 ret
= update_desktop_wallpaper();
4153 case SPI_SETDESKPATTERN
:
4154 if (!ptr
|| set_entry( &entry_DESKPATTERN
, val
, ptr
, winini
))
4155 ret
= update_desktop_wallpaper();
4157 case SPI_GETKEYBOARDDELAY
:
4158 ret
= get_entry( &entry_KEYBOARDDELAY
, val
, ptr
);
4160 case SPI_SETKEYBOARDDELAY
:
4161 ret
= set_entry( &entry_KEYBOARDDELAY
, val
, ptr
, winini
);
4163 case SPI_ICONVERTICALSPACING
:
4165 ret
= get_entry( &entry_ICONVERTICALSPACING
, val
, ptr
);
4168 int min_val
= map_to_dpi( 32, get_system_dpi() );
4169 ret
= set_entry( &entry_ICONVERTICALSPACING
, max( min_val
, val
), ptr
, winini
);
4172 case SPI_GETICONTITLEWRAP
:
4173 ret
= get_entry( &entry_ICONTITLEWRAP
, val
, ptr
);
4175 case SPI_SETICONTITLEWRAP
:
4176 ret
= set_entry( &entry_ICONTITLEWRAP
, val
, ptr
, winini
);
4178 case SPI_GETMENUDROPALIGNMENT
:
4179 ret
= get_entry( &entry_MENUDROPALIGNMENT
, val
, ptr
);
4181 case SPI_SETMENUDROPALIGNMENT
:
4182 ret
= set_entry( &entry_MENUDROPALIGNMENT
, val
, ptr
, winini
);
4184 case SPI_SETDOUBLECLKWIDTH
:
4185 ret
= set_entry( &entry_DOUBLECLKWIDTH
, val
, ptr
, winini
);
4187 case SPI_SETDOUBLECLKHEIGHT
:
4188 ret
= set_entry( &entry_DOUBLECLKHEIGHT
, val
, ptr
, winini
);
4190 case SPI_GETICONTITLELOGFONT
:
4191 ret
= get_entry( &entry_ICONTITLELOGFONT
, val
, ptr
);
4193 case SPI_SETDOUBLECLICKTIME
:
4194 ret
= set_entry( &entry_DOUBLECLICKTIME
, val
, ptr
, winini
);
4196 case SPI_SETMOUSEBUTTONSWAP
:
4197 ret
= set_entry( &entry_MOUSEBUTTONSWAP
, val
, ptr
, winini
);
4199 case SPI_SETICONTITLELOGFONT
:
4200 ret
= set_entry( &entry_ICONTITLELOGFONT
, val
, ptr
, winini
);
4202 case SPI_GETFASTTASKSWITCH
:
4203 if (!ptr
) return FALSE
;
4204 *(BOOL
*)ptr
= TRUE
;
4207 case SPI_SETFASTTASKSWITCH
:
4208 /* the action is disabled */
4211 case SPI_SETDRAGFULLWINDOWS
:
4212 ret
= set_entry( &entry_DRAGFULLWINDOWS
, val
, ptr
, winini
);
4214 case SPI_GETDRAGFULLWINDOWS
:
4215 ret
= get_entry( &entry_DRAGFULLWINDOWS
, val
, ptr
);
4217 case SPI_GETNONCLIENTMETRICS
:
4219 NONCLIENTMETRICSW
*nm
= ptr
;
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
);
4241 nm
->iBorderWidth
+= padded_border
;
4242 if (nm
->cbSize
== sizeof(NONCLIENTMETRICSW
)) nm
->iPaddedBorderWidth
= 0;
4244 normalize_nonclientmetrics( nm
);
4247 case SPI_SETNONCLIENTMETRICS
:
4249 LPNONCLIENTMETRICSW nm
= ptr
;
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
);
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;
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
);
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
);
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
);
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
;
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
;
4348 unlock_display_devices();
4349 spi_loaded
[spi_idx
] = TRUE
;
4351 *(RECT
*)ptr
= map_dpi_rect( work_area
, system_dpi
, get_thread_dpi() );
4353 TRACE("work area %s\n", wine_dbgstr_rect( &work_area
));
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;
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;
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;
4410 WINE_SPI_FIXME(SPI_SETMOUSEKEYS
);
4412 case SPI_GETSHOWSOUNDS
:
4413 ret
= get_entry( &entry_SHOWSOUNDS
, val
, ptr
);
4415 case SPI_SETSHOWSOUNDS
:
4416 ret
= set_entry( &entry_SHOWSOUNDS
, val
, ptr
, winini
);
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;
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;
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;
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;
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
;
4507 WINE_SPI_FIXME(SPI_SETHIGHCONTRAST
);
4509 case SPI_GETKEYBOARDPREF
:
4510 ret
= get_entry( &entry_KEYBOARDPREF
, val
, ptr
);
4512 case SPI_SETKEYBOARDPREF
:
4513 ret
= set_entry( &entry_KEYBOARDPREF
, val
, ptr
, winini
);
4515 case SPI_GETSCREENREADER
:
4516 ret
= get_entry( &entry_SCREENREADER
, val
, ptr
);
4518 case SPI_SETSCREENREADER
:
4519 ret
= set_entry( &entry_SCREENREADER
, val
, ptr
, winini
);
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;
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);
4542 case SPI_SETFONTSMOOTHING
:
4543 val
= val
? 2 : 0; /* Win NT4/2k/XP behavior */
4544 ret
= set_entry( &entry_FONTSMOOTHING
, val
, ptr
, winini
);
4546 case SPI_SETDRAGWIDTH
:
4547 ret
= set_entry( &entry_DRAGWIDTH
, val
, ptr
, winini
);
4549 case SPI_SETDRAGHEIGHT
:
4550 ret
= set_entry( &entry_DRAGHEIGHT
, val
, ptr
, winini
);
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
);
4562 case SPI_SETLOWPOWERACTIVE
:
4563 ret
= set_entry( &entry_LOWPOWERACTIVE
, val
, ptr
, winini
);
4565 case SPI_GETPOWEROFFACTIVE
:
4566 ret
= get_entry( &entry_POWEROFFACTIVE
, val
, ptr
);
4568 case SPI_SETPOWEROFFACTIVE
:
4569 ret
= set_entry( &entry_POWEROFFACTIVE
, val
, ptr
, winini
);
4572 WINE_SPI_FIXME(SPI_SETCURSORS
);
4573 WINE_SPI_FIXME(SPI_SETICONS
);
4575 case SPI_GETDEFAULTINPUTLANG
:
4576 ret
= NtUserGetKeyboardLayout(0) != 0;
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 */
4586 case SPI_SETMOUSETRAILS
:
4587 ret
= set_entry( &entry_MOUSETRAILS
, val
, ptr
, winini
);
4589 case SPI_GETMOUSETRAILS
:
4590 ret
= get_entry( &entry_MOUSETRAILS
, val
, ptr
);
4592 case SPI_GETSNAPTODEFBUTTON
:
4593 ret
= get_entry( &entry_SNAPTODEFBUTTON
, val
, ptr
);
4595 case SPI_SETSNAPTODEFBUTTON
:
4596 ret
= set_entry( &entry_SNAPTODEFBUTTON
, val
, ptr
, winini
);
4598 case SPI_SETSCREENSAVERRUNNING
:
4599 ret
= set_entry( &entry_SCREENSAVERRUNNING
, val
, ptr
, winini
);
4601 case SPI_GETMOUSEHOVERWIDTH
:
4602 ret
= get_entry( &entry_MOUSEHOVERWIDTH
, val
, ptr
);
4604 case SPI_SETMOUSEHOVERWIDTH
:
4605 ret
= set_entry( &entry_MOUSEHOVERWIDTH
, val
, ptr
, winini
);
4607 case SPI_GETMOUSEHOVERHEIGHT
:
4608 ret
= get_entry( &entry_MOUSEHOVERHEIGHT
, val
, ptr
);
4610 case SPI_SETMOUSEHOVERHEIGHT
:
4611 ret
= set_entry( &entry_MOUSEHOVERHEIGHT
, val
, ptr
, winini
);
4613 case SPI_GETMOUSEHOVERTIME
:
4614 ret
= get_entry( &entry_MOUSEHOVERTIME
, val
, ptr
);
4616 case SPI_SETMOUSEHOVERTIME
:
4617 ret
= set_entry( &entry_MOUSEHOVERTIME
, val
, ptr
, winini
);
4619 case SPI_GETWHEELSCROLLLINES
:
4620 ret
= get_entry( &entry_WHEELSCROLLLINES
, val
, ptr
);
4622 case SPI_SETWHEELSCROLLLINES
:
4623 ret
= set_entry( &entry_WHEELSCROLLLINES
, val
, ptr
, winini
);
4625 case SPI_GETMENUSHOWDELAY
:
4626 ret
= get_entry( &entry_MENUSHOWDELAY
, val
, ptr
);
4628 case SPI_SETMENUSHOWDELAY
:
4629 ret
= set_entry( &entry_MENUSHOWDELAY
, val
, ptr
, winini
);
4631 case SPI_GETWHEELSCROLLCHARS
:
4632 ret
= get_entry( &entry_WHEELSCROLLCHARS
, val
, ptr
);
4634 case SPI_SETWHEELSCROLLCHARS
:
4635 ret
= set_entry( &entry_WHEELSCROLLCHARS
, val
, ptr
, winini
);
4638 WINE_SPI_FIXME(SPI_GETSHOWIMEUI
);
4639 WINE_SPI_FIXME(SPI_SETSHOWIMEUI
);
4641 case SPI_GETMOUSESPEED
:
4642 ret
= get_entry( &entry_MOUSESPEED
, val
, ptr
);
4644 case SPI_SETMOUSESPEED
:
4645 ret
= set_entry( &entry_MOUSESPEED
, val
, ptr
, winini
);
4647 case SPI_GETSCREENSAVERRUNNING
:
4648 ret
= get_entry( &entry_SCREENSAVERRUNNING
, val
, ptr
);
4650 case SPI_GETDESKWALLPAPER
:
4651 ret
= get_entry( &entry_DESKWALLPAPER
, val
, ptr
);
4653 case SPI_GETACTIVEWINDOWTRACKING
:
4654 ret
= get_entry( &entry_ACTIVEWINDOWTRACKING
, val
, ptr
);
4656 case SPI_SETACTIVEWINDOWTRACKING
:
4657 ret
= set_entry( &entry_ACTIVEWINDOWTRACKING
, val
, ptr
, winini
);
4659 case SPI_GETMENUANIMATION
:
4660 ret
= get_entry( &entry_MENUANIMATION
, val
, ptr
);
4662 case SPI_SETMENUANIMATION
:
4663 ret
= set_entry( &entry_MENUANIMATION
, val
, ptr
, winini
);
4665 case SPI_GETCOMBOBOXANIMATION
:
4666 ret
= get_entry( &entry_COMBOBOXANIMATION
, val
, ptr
);
4668 case SPI_SETCOMBOBOXANIMATION
:
4669 ret
= set_entry( &entry_COMBOBOXANIMATION
, val
, ptr
, winini
);
4671 case SPI_GETLISTBOXSMOOTHSCROLLING
:
4672 ret
= get_entry( &entry_LISTBOXSMOOTHSCROLLING
, val
, ptr
);
4674 case SPI_SETLISTBOXSMOOTHSCROLLING
:
4675 ret
= set_entry( &entry_LISTBOXSMOOTHSCROLLING
, val
, ptr
, winini
);
4677 case SPI_GETGRADIENTCAPTIONS
:
4678 ret
= get_entry( &entry_GRADIENTCAPTIONS
, val
, ptr
);
4680 case SPI_SETGRADIENTCAPTIONS
:
4681 ret
= set_entry( &entry_GRADIENTCAPTIONS
, val
, ptr
, winini
);
4683 case SPI_GETKEYBOARDCUES
:
4684 ret
= get_entry( &entry_KEYBOARDCUES
, val
, ptr
);
4686 case SPI_SETKEYBOARDCUES
:
4687 ret
= set_entry( &entry_KEYBOARDCUES
, val
, ptr
, winini
);
4689 case SPI_GETACTIVEWNDTRKZORDER
:
4690 ret
= get_entry( &entry_ACTIVEWNDTRKZORDER
, val
, ptr
);
4692 case SPI_SETACTIVEWNDTRKZORDER
:
4693 ret
= set_entry( &entry_ACTIVEWNDTRKZORDER
, val
, ptr
, winini
);
4695 case SPI_GETHOTTRACKING
:
4696 ret
= get_entry( &entry_HOTTRACKING
, val
, ptr
);
4698 case SPI_SETHOTTRACKING
:
4699 ret
= set_entry( &entry_HOTTRACKING
, val
, ptr
, winini
);
4701 case SPI_GETMENUFADE
:
4702 ret
= get_entry( &entry_MENUFADE
, val
, ptr
);
4704 case SPI_SETMENUFADE
:
4705 ret
= set_entry( &entry_MENUFADE
, val
, ptr
, winini
);
4707 case SPI_GETSELECTIONFADE
:
4708 ret
= get_entry( &entry_SELECTIONFADE
, val
, ptr
);
4710 case SPI_SETSELECTIONFADE
:
4711 ret
= set_entry( &entry_SELECTIONFADE
, val
, ptr
, winini
);
4713 case SPI_GETTOOLTIPANIMATION
:
4714 ret
= get_entry( &entry_TOOLTIPANIMATION
, val
, ptr
);
4716 case SPI_SETTOOLTIPANIMATION
:
4717 ret
= set_entry( &entry_TOOLTIPANIMATION
, val
, ptr
, winini
);
4719 case SPI_GETTOOLTIPFADE
:
4720 ret
= get_entry( &entry_TOOLTIPFADE
, val
, ptr
);
4722 case SPI_SETTOOLTIPFADE
:
4723 ret
= set_entry( &entry_TOOLTIPFADE
, val
, ptr
, winini
);
4725 case SPI_GETCURSORSHADOW
:
4726 ret
= get_entry( &entry_CURSORSHADOW
, val
, ptr
);
4728 case SPI_SETCURSORSHADOW
:
4729 ret
= set_entry( &entry_CURSORSHADOW
, val
, ptr
, winini
);
4731 case SPI_GETMOUSESONAR
:
4732 ret
= get_entry( &entry_MOUSESONAR
, val
, ptr
);
4734 case SPI_SETMOUSESONAR
:
4735 ret
= set_entry( &entry_MOUSESONAR
, val
, ptr
, winini
);
4737 case SPI_GETMOUSECLICKLOCK
:
4738 ret
= get_entry( &entry_MOUSECLICKLOCK
, val
, ptr
);
4740 case SPI_SETMOUSECLICKLOCK
:
4741 ret
= set_entry( &entry_MOUSECLICKLOCK
, val
, ptr
, winini
);
4743 case SPI_GETMOUSEVANISH
:
4744 ret
= get_entry( &entry_MOUSEVANISH
, val
, ptr
);
4746 case SPI_SETMOUSEVANISH
:
4747 ret
= set_entry( &entry_MOUSEVANISH
, val
, ptr
, winini
);
4749 case SPI_GETFLATMENU
:
4750 ret
= get_entry( &entry_FLATMENU
, val
, ptr
);
4752 case SPI_SETFLATMENU
:
4753 ret
= set_entry( &entry_FLATMENU
, val
, ptr
, winini
);
4755 case SPI_GETDROPSHADOW
:
4756 ret
= get_entry( &entry_DROPSHADOW
, val
, ptr
);
4758 case SPI_SETDROPSHADOW
:
4759 ret
= set_entry( &entry_DROPSHADOW
, val
, ptr
, winini
);
4761 case SPI_GETBLOCKSENDINPUTRESETS
:
4762 ret
= get_entry( &entry_BLOCKSENDINPUTRESETS
, val
, ptr
);
4764 case SPI_SETBLOCKSENDINPUTRESETS
:
4765 ret
= set_entry( &entry_BLOCKSENDINPUTRESETS
, val
, ptr
, winini
);
4767 case SPI_GETUIEFFECTS
:
4768 ret
= get_entry( &entry_UIEFFECTS
, val
, ptr
);
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
);
4774 case SPI_GETDISABLEOVERLAPPEDCONTENT
:
4775 ret
= get_entry( &entry_DISABLEOVERLAPPEDCONTENT
, val
, ptr
);
4777 case SPI_SETDISABLEOVERLAPPEDCONTENT
:
4778 ret
= set_entry( &entry_DISABLEOVERLAPPEDCONTENT
, val
, ptr
, winini
);
4780 case SPI_GETCLIENTAREAANIMATION
:
4781 ret
= get_entry( &entry_CLIENTAREAANIMATION
, val
, ptr
);
4783 case SPI_SETCLIENTAREAANIMATION
:
4784 ret
= set_entry( &entry_CLIENTAREAANIMATION
, val
, ptr
, winini
);
4786 case SPI_GETCLEARTYPE
:
4787 ret
= get_entry( &entry_CLEARTYPE
, val
, ptr
);
4789 case SPI_SETCLEARTYPE
:
4790 ret
= set_entry( &entry_CLEARTYPE
, val
, ptr
, winini
);
4792 case SPI_GETSPEECHRECOGNITION
:
4793 ret
= get_entry( &entry_SPEECHRECOGNITION
, val
, ptr
);
4795 case SPI_SETSPEECHRECOGNITION
:
4796 ret
= set_entry( &entry_SPEECHRECOGNITION
, val
, ptr
, winini
);
4798 case SPI_GETFOREGROUNDLOCKTIMEOUT
:
4799 ret
= get_entry( &entry_FOREGROUNDLOCKTIMEOUT
, val
, ptr
);
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
);
4806 case SPI_GETACTIVEWNDTRKTIMEOUT
:
4807 ret
= get_entry( &entry_ACTIVEWNDTRKTIMEOUT
, val
, ptr
);
4809 case SPI_SETACTIVEWNDTRKTIMEOUT
:
4810 ret
= get_entry( &entry_ACTIVEWNDTRKTIMEOUT
, val
, ptr
);
4812 case SPI_GETFOREGROUNDFLASHCOUNT
:
4813 ret
= get_entry( &entry_FOREGROUNDFLASHCOUNT
, val
, ptr
);
4815 case SPI_SETFOREGROUNDFLASHCOUNT
:
4816 ret
= set_entry( &entry_FOREGROUNDFLASHCOUNT
, val
, ptr
, winini
);
4818 case SPI_GETCARETWIDTH
:
4819 ret
= get_entry( &entry_CARETWIDTH
, val
, ptr
);
4821 case SPI_SETCARETWIDTH
:
4822 ret
= set_entry( &entry_CARETWIDTH
, val
, ptr
, winini
);
4824 case SPI_GETMOUSECLICKLOCKTIME
:
4825 ret
= get_entry( &entry_MOUSECLICKLOCKTIME
, val
, ptr
);
4827 case SPI_SETMOUSECLICKLOCKTIME
:
4828 ret
= set_entry( &entry_MOUSECLICKLOCKTIME
, val
, ptr
, winini
);
4830 case SPI_GETFONTSMOOTHINGTYPE
:
4831 ret
= get_entry( &entry_FONTSMOOTHINGTYPE
, val
, ptr
);
4833 case SPI_SETFONTSMOOTHINGTYPE
:
4834 ret
= set_entry( &entry_FONTSMOOTHINGTYPE
, val
, ptr
, winini
);
4836 case SPI_GETFONTSMOOTHINGCONTRAST
:
4837 ret
= get_entry( &entry_FONTSMOOTHINGCONTRAST
, val
, ptr
);
4839 case SPI_SETFONTSMOOTHINGCONTRAST
:
4840 ret
= set_entry( &entry_FONTSMOOTHINGCONTRAST
, val
, ptr
, winini
);
4842 case SPI_GETFOCUSBORDERWIDTH
:
4843 ret
= get_entry( &entry_FOCUSBORDERWIDTH
, val
, ptr
);
4845 case SPI_GETFOCUSBORDERHEIGHT
:
4846 ret
= get_entry( &entry_FOCUSBORDERHEIGHT
, val
, ptr
);
4848 case SPI_SETFOCUSBORDERWIDTH
:
4849 ret
= set_entry( &entry_FOCUSBORDERWIDTH
, val
, ptr
, winini
);
4851 case SPI_SETFOCUSBORDERHEIGHT
:
4852 ret
= set_entry( &entry_FOCUSBORDERHEIGHT
, val
, ptr
, winini
);
4854 case SPI_GETFONTSMOOTHINGORIENTATION
:
4855 ret
= get_entry( &entry_FONTSMOOTHINGORIENTATION
, val
, ptr
);
4857 case SPI_SETFONTSMOOTHINGORIENTATION
:
4858 ret
= set_entry( &entry_FONTSMOOTHINGORIENTATION
, val
, ptr
, winini
);
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
);
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
);
4881 FIXME( "Unknown action: %u\n", action
);
4882 RtlSetLastWin32Error( ERROR_INVALID_SPI_VALUE
);
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
);
4897 #undef WINE_SPI_FIXME
4898 #undef WINE_SPI_WARN
4901 int get_system_metrics( int index
)
4903 NONCLIENTMETRICSW ncm
;
4904 MINIMIZEDMETRICS mm
;
4910 /* some metrics are dynamic */
4915 get_entry( &entry_SCROLLWIDTH
, 0, &ret
);
4916 return max( ret
, 8 );
4918 ncm
.cbSize
= sizeof(ncm
);
4919 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
4920 return ncm
.iCaptionHeight
+ 1;
4923 /* SM_C{X,Y}BORDER always returns 1 regardless of 'BorderWidth' value in registry */
4932 get_entry( &entry_SCROLLHEIGHT
, 0, &ret
);
4933 return max( ret
, 8 );
4936 return map_to_dpi( 32, get_system_dpi() );
4939 ret
= map_to_dpi( 32, get_system_dpi() );
4940 if (ret
>= 64) return 64;
4941 if (ret
>= 48) return 48;
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
4953 return get_system_metrics( SM_CYMAXIMIZED
) - get_system_metrics( SM_CYMIN
);
4954 case SM_CYKANJIWINDOW
:
4956 case SM_MOUSEPRESENT
:
4961 get_entry( &entry_MOUSEBUTTONSWAP
, 0, &ret
);
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;
4977 return get_system_metrics( SM_CYCAPTION
) + 2 * get_system_metrics( SM_CYFRAME
);
4979 get_entry( &entry_CAPTIONWIDTH
, 0, &ret
);
4980 return max( ret
, 8 );
4982 ncm
.cbSize
= sizeof(ncm
);
4983 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
4984 return ncm
.iCaptionHeight
;
4986 get_entry( &entry_BORDER
, 0, &ret
);
4987 ret
= max( ret
, 1 );
4988 return get_system_metrics( SM_CXDLGFRAME
) + ret
;
4990 get_entry( &entry_BORDER
, 0, &ret
);
4991 ret
= max( ret
, 1 );
4992 return get_system_metrics( SM_CYDLGFRAME
) + ret
;
4994 return get_system_metrics( SM_CXMIN
);
4996 return get_system_metrics( SM_CYMIN
);
4997 case SM_CXDOUBLECLK
:
4998 get_entry( &entry_DOUBLECLKWIDTH
, 0, &ret
);
5000 case SM_CYDOUBLECLK
:
5001 get_entry( &entry_DOUBLECLKHEIGHT
, 0, &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 );
5016 case SM_DBCSENABLED
:
5017 return ansi_cp
.MaximumCharacterSize
> 1;
5018 case SM_CMOUSEBUTTONS
:
5023 return get_system_metrics( SM_CXBORDER
) + 1;
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
;
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;
5042 get_entry( &entry_SMCAPTIONWIDTH
, 0, &ret
);
5045 ncm
.cbSize
= sizeof(ncm
);
5046 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5047 return ncm
.iSmCaptionHeight
;
5049 get_entry( &entry_MENUWIDTH
, 0, &ret
);
5052 ncm
.cbSize
= sizeof(ncm
);
5053 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5054 return ncm
.iMenuHeight
;
5056 mm
.cbSize
= sizeof(mm
);
5057 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(mm
), &mm
, 0 );
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;
5068 return get_system_metrics( SM_CXVIRTUALSCREEN
) + 4 + 2 * get_system_metrics( SM_CXFRAME
);
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
);
5078 return 3; /* FIXME */
5080 return 0; /* 0 = ok, 1 = failsafe, 2 = failsafe + network */
5082 get_entry( &entry_DRAGWIDTH
, 0, &ret
);
5085 get_entry( &entry_DRAGHEIGHT
, 0, &ret
);
5088 get_entry( &entry_SHOWSOUNDS
, 0, &ret
);
5090 case SM_CXMENUCHECK
:
5091 case SM_CYMENUCHECK
:
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
:
5108 rect
= get_primary_monitor_rect( get_thread_dpi() );
5109 return rect
.right
- rect
.left
;
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() );
5116 case SM_YVIRTUALSCREEN
:
5117 rect
= get_virtual_screen_rect( get_thread_dpi() );
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
;
5126 if (!lock_display_devices()) return FALSE
;
5127 ret
= active_monitor_count();
5128 unlock_display_devices();
5130 case SM_SAMEDISPLAYFORMAT
:
5133 return 0; /* FIXME */
5134 case SM_CXFOCUSBORDER
:
5135 case SM_CYFOCUSBORDER
:
5138 case SM_MEDIACENTER
:
5147 static int get_system_metrics_for_dpi( int index
, unsigned int dpi
)
5149 NONCLIENTMETRICSW ncm
;
5154 /* some metrics are dynamic */
5159 get_entry_dpi( &entry_SCROLLWIDTH
, 0, &ret
, dpi
);
5160 return max( ret
, 8 );
5162 ncm
.cbSize
= sizeof(ncm
);
5163 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5164 return ncm
.iCaptionHeight
+ 1;
5169 get_entry_dpi( &entry_SCROLLHEIGHT
, 0, &ret
, dpi
);
5170 return max( ret
, 8 );
5173 return map_to_dpi( 32, dpi
);
5176 ret
= map_to_dpi( 32, dpi
);
5177 if (ret
>= 64) return 64;
5178 if (ret
>= 48) return 48;
5181 ncm
.cbSize
= sizeof(ncm
);
5182 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5183 return ncm
.iMenuHeight
+ 1;
5185 get_entry_dpi( &entry_CAPTIONWIDTH
, 0, &ret
, dpi
);
5186 return max( ret
, 8 );
5188 ncm
.cbSize
= sizeof(ncm
);
5189 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5190 return ncm
.iCaptionHeight
;
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
;
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
;
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;
5215 get_entry_dpi( &entry_SMCAPTIONWIDTH
, 0, &ret
, dpi
);
5218 ncm
.cbSize
= sizeof(ncm
);
5219 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5220 return ncm
.iSmCaptionHeight
;
5222 get_entry_dpi( &entry_MENUWIDTH
, 0, &ret
, dpi
);
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
:
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);
5240 return get_system_metrics( index
);
5244 COLORREF
get_sys_color( int index
)
5248 if (index
>= 0 && index
< ARRAY_SIZE( system_colors
))
5249 get_entry( &system_colors
[index
], 0, &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
;
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
);
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)
5315 get_entry( &entry_DOUBLECLICKTIME
, 0, &time
);
5316 if (!time
) time
= 500;
5320 /*************************************************************************
5321 * NtUserSetSysColors (win32u.@)
5323 BOOL WINAPI
NtUserSetSysColors( INT count
, const INT
*colors
, const COLORREF
*values
)
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
);
5342 static LONG dpi_awareness
;
5344 /***********************************************************************
5345 * NtUserSetProcessDpiAwarenessContext (win32u.@)
5347 BOOL WINAPI
NtUserSetProcessDpiAwarenessContext( ULONG awareness
, ULONG unknown
)
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
:
5358 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
5362 return !InterlockedCompareExchange( &dpi_awareness
, awareness
, 0 );
5365 /***********************************************************************
5366 * NtUserGetProcessDpiAwarenessContext (win32u.@)
5368 ULONG WINAPI
NtUserGetProcessDpiAwarenessContext( HANDLE process
)
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
;
5383 BOOL
message_beep( UINT i
)
5386 NtUserSystemParametersInfo( SPI_GETBEEP
, 0, &active
, FALSE
);
5387 if (active
) user_driver
->pBeep();
5391 static DWORD exiting_thread_id
;
5393 /**********************************************************************
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
)
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();
5451 case NtUserThreadDetach
:
5456 FIXME( "invalid code %u\n", (int)code
);
5461 /***********************************************************************
5462 * NtUserCallOneParam (win32u.@)
5464 ULONG_PTR WINAPI
NtUserCallOneParam( ULONG_PTR arg
, ULONG 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
;
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 );
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 );
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
;
5538 /* temporary exports */
5539 case NtUserGetDeskPattern
:
5540 return get_entry( &entry_DESKPATTERN
, 256, (WCHAR
*)arg
);
5543 FIXME( "invalid code %u\n", (int)code
);
5548 /***********************************************************************
5549 * NtUserCallTwoParam (win32u.@)
5551 ULONG_PTR WINAPI
NtUserCallTwoParam( ULONG_PTR arg1
, ULONG_PTR arg2
, ULONG 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
);
5584 FIXME( "invalid code %u\n", (int)code
);
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
;
5625 unlock_display_devices();
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
) ))
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
;
5659 unlock_display_devices();
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
:
5692 FIXME( "Unimplemented packet type %u.\n", packet
->type
);
5693 return STATUS_INVALID_PARAMETER
;