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"
37 #include "wine/wingdi16.h"
38 #include "wine/server.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(system
);
43 static HKEY video_key
, enum_key
, control_key
, config_key
, volatile_base_key
;
45 static const WCHAR devicemap_video_keyW
[] =
47 '\\','R','e','g','i','s','t','r','y',
48 '\\','M','a','c','h','i','n','e',
49 '\\','H','A','R','D','W','A','R','E',
50 '\\','D','E','V','I','C','E','M','A','P',
51 '\\','V','I','D','E','O'
54 static const WCHAR enum_keyW
[] =
56 '\\','R','e','g','i','s','t','r','y',
57 '\\','M','a','c','h','i','n','e',
58 '\\','S','y','s','t','e','m',
59 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
63 static const WCHAR control_keyW
[] =
65 '\\','R','e','g','i','s','t','r','y',
66 '\\','M','a','c','h','i','n','e',
67 '\\','S','y','s','t','e','m',
68 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
69 '\\','C','o','n','t','r','o','l'
72 static const WCHAR config_keyW
[] =
74 '\\','R','e','g','i','s','t','r','y',
75 '\\','M','a','c','h','i','n','e',
76 '\\','S','y','s','t','e','m',
77 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
78 '\\','H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s',
79 '\\','C','u','r','r','e','n','t'
82 static const WCHAR devpropkey_gpu_vulkan_uuidW
[] =
84 'P','r','o','p','e','r','t','i','e','s',
85 '\\','{','2','3','3','A','9','E','F','3','-','A','F','C','4','-','4','A','B','D',
86 '-','B','5','6','4','-','C','3','2','F','2','1','F','1','5','3','5','C','}',
90 static const WCHAR devpropkey_gpu_luidW
[] =
92 'P','r','o','p','e','r','t','i','e','s',
93 '\\','{','6','0','B','1','9','3','C','B','-','5','2','7','6','-','4','D','0','F',
94 '-','9','6','F','C','-','F','1','7','3','A','B','A','D','3','E','C','6','}',
98 static const WCHAR devpkey_device_matching_device_id
[] =
100 'P','r','o','p','e','r','t','i','e','s',
101 '\\','{','A','8','B','8','6','5','D','D','-','2','E','3','D','-','4','0','9','4',
102 '-','A','D','9','7','-','E','5','9','3','A','7','0','C','7','5','D','6','}',
106 static const WCHAR devpkey_device_bus_number
[] =
108 'P','r','o','p','e','r','t','i','e','s',
109 '\\','{','A','4','5','C','2','5','4','E','-','D','F','1','C','-','4','E','F','D',
110 '-','8','0','2','0','-','6','7','D','1','4','6','A','8','5','0','E','0','}',
114 static const WCHAR devpkey_device_removal_policy
[] =
116 'P','r','o','p','e','r','t','i','e','s',
117 '\\','{','A','4','5','C','2','5','4','E','-','D','F','1','C','-','4','E','F','D',
118 '-','8','0','2','0','-','6','7','D','1','4','6','A','8','5','0','E','0','}',
122 static const WCHAR devpropkey_device_ispresentW
[] =
124 'P','r','o','p','e','r','t','i','e','s',
125 '\\','{','5','4','0','B','9','4','7','E','-','8','B','4','0','-','4','5','B','C',
126 '-','A','8','A','2','-','6','A','0','B','8','9','4','C','B','D','A','2','}',
130 static const WCHAR devpropkey_monitor_gpu_luidW
[] =
132 'P','r','o','p','e','r','t','i','e','s',
133 '\\','{','C','A','0','8','5','8','5','3','-','1','6','C','E','-','4','8','A','A',
134 '-','B','1','1','4','-','D','E','9','C','7','2','3','3','4','2','2','3','}',
138 static const WCHAR devpropkey_monitor_output_idW
[] =
140 'P','r','o','p','e','r','t','i','e','s',
141 '\\','{','C','A','0','8','5','8','5','3','-','1','6','C','E','-','4','8','A','A',
142 '-','B','1','1','4','-','D','E','9','C','7','2','3','3','4','2','2','3','}',
146 static const WCHAR wine_devpropkey_monitor_stateflagsW
[] =
148 'P','r','o','p','e','r','t','i','e','s','\\',
149 '{','2','3','3','a','9','e','f','3','-','a','f','c','4','-','4','a','b','d',
150 '-','b','5','6','4','-','c','3','2','f','2','1','f','1','5','3','5','b','}',
154 static const WCHAR wine_devpropkey_monitor_rcmonitorW
[] =
156 'P','r','o','p','e','r','t','i','e','s','\\',
157 '{','2','3','3','a','9','e','f','3','-','a','f','c','4','-','4','a','b','d',
158 '-','b','5','6','4','-','c','3','2','f','2','1','f','1','5','3','5','b','}',
162 static const WCHAR wine_devpropkey_monitor_rcworkW
[] =
164 'P','r','o','p','e','r','t','i','e','s','\\',
165 '{','2','3','3','a','9','e','f','3','-','a','f','c','4','-','4','a','b','d',
166 '-','b','5','6','4','-','c','3','2','f','2','1','f','1','5','3','5','b','}',
170 static const WCHAR wine_devpropkey_monitor_adapternameW
[] =
172 'P','r','o','p','e','r','t','i','e','s','\\',
173 '{','2','3','3','a','9','e','f','3','-','a','f','c','4','-','4','a','b','d',
174 '-','b','5','6','4','-','c','3','2','f','2','1','f','1','5','3','5','b','}',
178 static const WCHAR device_instanceW
[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
179 static const WCHAR controlW
[] = {'C','o','n','t','r','o','l'};
180 static const WCHAR device_parametersW
[] =
181 {'D','e','v','i','c','e',' ','P','a','r','a','m','e','t','e','r','s'};
182 static const WCHAR linkedW
[] = {'L','i','n','k','e','d',0};
183 static const WCHAR symbolic_link_valueW
[] =
184 {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
185 static const WCHAR state_flagsW
[] = {'S','t','a','t','e','F','l','a','g','s',0};
186 static const WCHAR gpu_idW
[] = {'G','P','U','I','D',0};
187 static const WCHAR hardware_idW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
188 static const WCHAR device_descW
[] = {'D','e','v','i','c','e','D','e','s','c',0};
189 static const WCHAR driver_descW
[] = {'D','r','i','v','e','r','D','e','s','c',0};
190 static const WCHAR driverW
[] = {'D','r','i','v','e','r',0};
191 static const WCHAR class_guidW
[] = {'C','l','a','s','s','G','U','I','D',0};
192 static const WCHAR pciW
[] = {'P','C','I'};
193 static const WCHAR classW
[] = {'C','l','a','s','s',0};
194 static const WCHAR displayW
[] = {'D','i','s','p','l','a','y',0};
195 static const WCHAR monitorW
[] = {'M','o','n','i','t','o','r',0};
196 static const WCHAR yesW
[] = {'Y','e','s',0};
197 static const WCHAR noW
[] = {'N','o',0};
198 static const WCHAR mode_countW
[] = {'M','o','d','e','C','o','u','n','t',0};
199 static const WCHAR edidW
[] = {'E','D','I','D',0};
201 static const char guid_devclass_displayA
[] = "{4D36E968-E325-11CE-BFC1-08002BE10318}";
202 static const WCHAR guid_devclass_displayW
[] =
203 {'{','4','D','3','6','E','9','6','8','-','E','3','2','5','-','1','1','C','E','-',
204 'B','F','C','1','-','0','8','0','0','2','B','E','1','0','3','1','8','}',0};
206 static const char guid_devclass_monitorA
[] = "{4D36E96E-E325-11CE-BFC1-08002BE10318}";
207 static const WCHAR guid_devclass_monitorW
[] =
208 {'{','4','D','3','6','E','9','6','E','-','E','3','2','5','-','1','1','C','E','-',
209 'B','F','C','1','-','0','8','0','0','2','B','E','1','0','3','1','8','}',0};
211 static const WCHAR guid_devinterface_display_adapterW
[] =
212 {'{','5','B','4','5','2','0','1','D','-','F','2','F','2','-','4','F','3','B','-',
213 '8','5','B','B','-','3','0','F','F','1','F','9','5','3','5','9','9','}',0};
215 static const WCHAR guid_display_device_arrivalW
[] =
216 {'{','1','C','A','0','5','1','8','0','-','A','6','9','9','-','4','5','0','A','-',
217 '9','A','0','C','-','D','E','4','F','B','E','3','D','D','D','8','9','}',0};
219 static const WCHAR guid_devinterface_monitorW
[] =
220 {'{','E','6','F','0','7','B','5','F','-','E','E','9','7','-','4','A','9','0','-',
221 'B','0','7','6','-','3','3','F','5','7','B','F','4','E','A','A','7','}',0};
223 #define NEXT_DEVMODEW(mode) ((DEVMODEW *)((char *)((mode) + 1) + (mode)->dmDriverExtra))
225 /* Cached display device information */
226 struct display_device
228 WCHAR device_name
[32]; /* DeviceName in DISPLAY_DEVICEW */
229 WCHAR device_string
[128]; /* DeviceString in DISPLAY_DEVICEW */
230 DWORD state_flags
; /* StateFlags in DISPLAY_DEVICEW */
231 WCHAR device_id
[128]; /* DeviceID in DISPLAY_DEVICEW */
232 WCHAR interface_name
[128]; /* DeviceID in DISPLAY_DEVICEW when EDD_GET_DEVICE_INTERFACE_NAME is set */
233 WCHAR device_key
[128]; /* DeviceKey in DISPLAY_DEVICEW */
240 struct display_device dev
;
243 const WCHAR
*config_key
;
244 unsigned int mode_count
;
248 #define MONITOR_INFO_HAS_MONITOR_ID 0x00000001
249 #define MONITOR_INFO_HAS_MONITOR_NAME 0x00000002
250 #define MONITOR_INFO_HAS_PREFERRED_MODE 0x00000004
251 struct edid_monitor_info
254 /* MONITOR_INFO_HAS_MONITOR_ID */
255 unsigned short manufacturer
, product_code
;
256 char monitor_id_string
[8];
257 /* MONITOR_INFO_HAS_MONITOR_NAME */
258 WCHAR monitor_name
[14];
259 /* MONITOR_INFO_HAS_PREFERRED_MODE */
260 unsigned int preferred_width
, preferred_height
;
266 struct display_device dev
;
267 struct adapter
*adapter
;
271 unsigned int output_id
;
275 struct edid_monitor_info edid_info
;
278 static struct list adapters
= LIST_INIT(adapters
);
279 static struct list monitors
= LIST_INIT(monitors
);
280 static INT64 last_query_display_time
;
281 static pthread_mutex_t display_lock
= PTHREAD_MUTEX_INITIALIZER
;
283 BOOL enable_thunk_lock
= FALSE
;
285 #define VIRTUAL_HMONITOR ((HMONITOR)(UINT_PTR)(0x10000 + 1))
286 static struct monitor virtual_monitor
=
288 .handle
= VIRTUAL_HMONITOR
,
289 .flags
= MONITORINFOF_PRIMARY
,
290 .rc_monitor
.right
= 1024,
291 .rc_monitor
.bottom
= 768,
292 .rc_work
.right
= 1024,
293 .rc_work
.bottom
= 768,
294 .dev
.state_flags
= DISPLAY_DEVICE_ACTIVE
| DISPLAY_DEVICE_ATTACHED
,
297 /* the various registry keys that are used to store parameters */
314 static const char *parameter_key_names
[NB_PARAM_KEYS
] =
316 "Control Panel\\Colors",
317 "Control Panel\\Desktop",
318 "Control Panel\\Keyboard",
319 "Control Panel\\Mouse",
320 "Control Panel\\Desktop\\WindowMetrics",
321 "Control Panel\\Sound",
322 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows",
323 "Control Panel\\Accessibility\\ShowSounds",
324 "Control Panel\\Accessibility\\Keyboard Preference",
325 "Control Panel\\Accessibility\\Blind Access",
326 "Control Panel\\Accessibility\\AudioDescription",
329 /* System parameters storage */
330 union sysparam_all_entry
;
332 struct sysparam_entry
334 BOOL (*get
)( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
);
335 BOOL (*set
)( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
);
336 BOOL (*init
)( union sysparam_all_entry
*entry
);
337 enum parameter_key base_key
;
339 enum parameter_key mirror_key
;
344 struct sysparam_uint_entry
346 struct sysparam_entry hdr
;
350 struct sysparam_bool_entry
352 struct sysparam_entry hdr
;
356 struct sysparam_dword_entry
358 struct sysparam_entry hdr
;
362 struct sysparam_rgb_entry
364 struct sysparam_entry hdr
;
370 struct sysparam_binary_entry
372 struct sysparam_entry hdr
;
377 struct sysparam_path_entry
379 struct sysparam_entry hdr
;
383 struct sysparam_font_entry
385 struct sysparam_entry hdr
;
388 WCHAR fullname
[LF_FACESIZE
];
391 struct sysparam_pref_entry
393 struct sysparam_entry hdr
;
394 union sysparam_all_entry
*parent
;
399 union sysparam_all_entry
401 struct sysparam_entry hdr
;
402 struct sysparam_uint_entry uint
;
403 struct sysparam_bool_entry
bool;
404 struct sysparam_dword_entry dword
;
405 struct sysparam_rgb_entry rgb
;
406 struct sysparam_binary_entry bin
;
407 struct sysparam_path_entry path
;
408 struct sysparam_font_entry font
;
409 struct sysparam_pref_entry pref
;
412 static UINT system_dpi
;
413 static RECT work_area
;
414 static DWORD process_layout
= ~0u;
416 static HDC display_dc
;
417 static pthread_mutex_t display_dc_lock
= PTHREAD_MUTEX_INITIALIZER
;
419 static pthread_mutex_t user_mutex
;
420 static unsigned int user_lock_thread
, user_lock_rec
;
424 pthread_mutex_lock( &user_mutex
);
425 if (!user_lock_rec
++) user_lock_thread
= GetCurrentThreadId();
428 void user_unlock(void)
430 if (!--user_lock_rec
) user_lock_thread
= 0;
431 pthread_mutex_unlock( &user_mutex
);
434 void user_check_not_lock(void)
436 if (user_lock_thread
== GetCurrentThreadId())
438 ERR( "BUG: holding USER lock\n" );
443 static HANDLE
get_display_device_init_mutex( void )
446 UNICODE_STRING name
= {.Buffer
= bufferW
};
447 OBJECT_ATTRIBUTES attr
;
451 snprintf( buffer
, ARRAY_SIZE(buffer
), "\\Sessions\\%u\\BaseNamedObjects\\display_device_init",
452 (int)NtCurrentTeb()->Peb
->SessionId
);
453 name
.MaximumLength
= asciiz_to_unicode( bufferW
, buffer
);
454 name
.Length
= name
.MaximumLength
- sizeof(WCHAR
);
456 InitializeObjectAttributes( &attr
, &name
, OBJ_OPENIF
, NULL
, NULL
);
457 if (NtCreateMutant( &mutex
, MUTEX_ALL_ACCESS
, &attr
, FALSE
) < 0) return 0;
458 NtWaitForSingleObject( mutex
, FALSE
, NULL
);
462 static void release_display_device_init_mutex( HANDLE mutex
)
464 NtReleaseMutant( mutex
, NULL
);
468 static struct adapter
*adapter_acquire( struct adapter
*adapter
)
470 InterlockedIncrement( &adapter
->refcount
);
474 static void adapter_release( struct adapter
*adapter
)
476 if (!InterlockedDecrement( &adapter
->refcount
))
478 free( adapter
->modes
);
483 C_ASSERT(sizeof(DEVMODEW
) - offsetof(DEVMODEW
, dmFields
) == 0x94);
485 static void get_monitor_info_from_edid( struct edid_monitor_info
*info
, const unsigned char *edid
, unsigned int edid_len
)
493 if (!edid
|| edid_len
< 128) return;
495 w
= (edid
[8] << 8) | edid
[9]; /* Manufacturer ID, big endian. */
496 for (i
= 0; i
< 3; ++i
)
499 if (!d
|| d
- 1 > 'Z' - 'A') return;
500 info
->monitor_id_string
[2 - i
] = 'A' + d
- 1;
504 w
= edid
[10] | (edid
[11] << 8); /* Product code, little endian. */
505 info
->manufacturer
= *(unsigned short *)(edid
+ 8);
506 info
->product_code
= w
;
507 sprintf( info
->monitor_id_string
+ 3, "%04X", w
);
508 info
->flags
= MONITOR_INFO_HAS_MONITOR_ID
;
509 TRACE( "Monitor id %s.\n", info
->monitor_id_string
);
511 for (i
= 0; i
< 4; ++i
)
513 if (edid
[54 + i
* 18] || edid
[54 + i
* 18 + 1])
515 /* Detailed timing descriptor. */
516 if (info
->flags
& MONITOR_INFO_HAS_PREFERRED_MODE
) continue;
517 info
->preferred_width
= edid
[54 + i
* 18 + 2] | ((UINT32
)(edid
[54 + i
* 18 + 4] & 0xf0) << 4);
518 info
->preferred_height
= edid
[54 + i
* 18 + 5] | ((UINT32
)(edid
[54 + i
* 18 + 7] & 0xf0) << 4);
519 if (info
->preferred_width
&& info
->preferred_height
)
520 info
->flags
|= MONITOR_INFO_HAS_PREFERRED_MODE
;
523 if (edid
[54 + i
* 18 + 3] != 0xfc) continue;
524 /* "Display name" ASCII descriptor. */
525 s
= (const char *)&edid
[54 + i
* 18 + 5];
526 for (j
= 0; s
[j
] && j
< 13; ++j
)
527 info
->monitor_name
[j
] = s
[j
];
528 while (j
&& isspace(s
[j
- 1])) --j
;
529 info
->monitor_name
[j
] = 0;
530 info
->flags
|= MONITOR_INFO_HAS_MONITOR_NAME
;
535 static BOOL
write_adapter_mode( HKEY adapter_key
, UINT index
, const DEVMODEW
*mode
)
537 WCHAR bufferW
[MAX_PATH
] = {0};
538 char buffer
[MAX_PATH
];
540 sprintf( buffer
, "Modes\\%08X", index
);
541 asciiz_to_unicode( bufferW
, buffer
);
542 return set_reg_value( adapter_key
, bufferW
, REG_BINARY
, &mode
->dmFields
, sizeof(*mode
) - offsetof(DEVMODEW
, dmFields
) );
545 static BOOL
read_adapter_mode( HKEY adapter_key
, UINT index
, DEVMODEW
*mode
)
547 char value_buf
[offsetof(KEY_VALUE_PARTIAL_INFORMATION
, Data
[sizeof(*mode
)])];
548 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)value_buf
;
549 WCHAR bufferW
[MAX_PATH
] = {0};
550 char buffer
[MAX_PATH
];
552 sprintf( buffer
, "Modes\\%08X", index
);
553 asciiz_to_unicode( bufferW
, buffer
);
554 if (!query_reg_value( adapter_key
, bufferW
, value
, sizeof(value_buf
) )) return FALSE
;
556 memcpy( &mode
->dmFields
, value
->Data
, sizeof(*mode
) - offsetof(DEVMODEW
, dmFields
) );
560 static BOOL
adapter_get_registry_settings( const struct adapter
*adapter
, DEVMODEW
*mode
)
566 mutex
= get_display_device_init_mutex();
568 if (!config_key
&& !(config_key
= reg_open_key( NULL
, config_keyW
, sizeof(config_keyW
) ))) ret
= FALSE
;
569 else if (!(hkey
= reg_open_key( config_key
, adapter
->config_key
, lstrlenW( adapter
->config_key
) * sizeof(WCHAR
) ))) ret
= FALSE
;
572 ret
= read_adapter_mode( hkey
, ENUM_REGISTRY_SETTINGS
, mode
);
576 release_display_device_init_mutex( mutex
);
580 static BOOL
adapter_set_registry_settings( const struct adapter
*adapter
, const DEVMODEW
*mode
)
586 mutex
= get_display_device_init_mutex();
588 if (!config_key
&& !(config_key
= reg_open_key( NULL
, config_keyW
, sizeof(config_keyW
) ))) ret
= FALSE
;
589 if (!(hkey
= reg_open_key( config_key
, adapter
->config_key
, lstrlenW( adapter
->config_key
) * sizeof(WCHAR
) ))) ret
= FALSE
;
592 ret
= write_adapter_mode( hkey
, ENUM_REGISTRY_SETTINGS
, mode
);
596 release_display_device_init_mutex( mutex
);
600 static BOOL
adapter_get_current_settings( const struct adapter
*adapter
, DEVMODEW
*mode
)
602 BOOL is_primary
= !!(adapter
->dev
.state_flags
& DISPLAY_DEVICE_PRIMARY_DEVICE
);
607 /* use the default implementation in virtual desktop mode */
608 if (is_virtual_desktop()) ret
= FALSE
;
609 else ret
= user_driver
->pGetCurrentDisplaySettings( adapter
->dev
.device_name
, is_primary
, mode
);
611 if (ret
) return TRUE
;
613 /* default implementation: read current display settings from the registry. */
615 mutex
= get_display_device_init_mutex();
617 if (!config_key
&& !(config_key
= reg_open_key( NULL
, config_keyW
, sizeof(config_keyW
) ))) ret
= FALSE
;
618 else if (!(hkey
= reg_open_key( config_key
, adapter
->config_key
, lstrlenW( adapter
->config_key
) * sizeof(WCHAR
) ))) ret
= FALSE
;
621 ret
= read_adapter_mode( hkey
, ENUM_CURRENT_SETTINGS
, mode
);
625 release_display_device_init_mutex( mutex
);
629 static BOOL
adapter_set_current_settings( const struct adapter
*adapter
, const DEVMODEW
*mode
)
635 mutex
= get_display_device_init_mutex();
637 if (!config_key
&& !(config_key
= reg_open_key( NULL
, config_keyW
, sizeof(config_keyW
) ))) ret
= FALSE
;
638 if (!(hkey
= reg_open_key( config_key
, adapter
->config_key
, lstrlenW( adapter
->config_key
) * sizeof(WCHAR
) ))) ret
= FALSE
;
641 ret
= write_adapter_mode( hkey
, ENUM_CURRENT_SETTINGS
, mode
);
645 release_display_device_init_mutex( mutex
);
649 static int mode_compare(const void *p1
, const void *p2
)
651 BOOL a_interlaced
, b_interlaced
, a_stretched
, b_stretched
;
652 DWORD a_width
, a_height
, b_width
, b_height
;
653 const DEVMODEW
*a
= p1
, *b
= p2
;
656 /* Depth in descending order */
657 if ((ret
= b
->dmBitsPerPel
- a
->dmBitsPerPel
)) return ret
;
659 /* Use the width and height in landscape mode for comparison */
660 if (a
->dmDisplayOrientation
== DMDO_DEFAULT
|| a
->dmDisplayOrientation
== DMDO_180
)
662 a_width
= a
->dmPelsWidth
;
663 a_height
= a
->dmPelsHeight
;
667 a_width
= a
->dmPelsHeight
;
668 a_height
= a
->dmPelsWidth
;
671 if (b
->dmDisplayOrientation
== DMDO_DEFAULT
|| b
->dmDisplayOrientation
== DMDO_180
)
673 b_width
= b
->dmPelsWidth
;
674 b_height
= b
->dmPelsHeight
;
678 b_width
= b
->dmPelsHeight
;
679 b_height
= b
->dmPelsWidth
;
682 /* Width in ascending order */
683 if ((ret
= a_width
- b_width
)) return ret
;
685 /* Height in ascending order */
686 if ((ret
= a_height
- b_height
)) return ret
;
688 /* Frequency in descending order */
689 if ((ret
= b
->dmDisplayFrequency
- a
->dmDisplayFrequency
)) return ret
;
691 /* Orientation in ascending order */
692 if ((ret
= a
->dmDisplayOrientation
- b
->dmDisplayOrientation
)) return ret
;
694 if (!(a
->dmFields
& DM_DISPLAYFLAGS
)) a_interlaced
= FALSE
;
695 else a_interlaced
= !!(a
->dmDisplayFlags
& DM_INTERLACED
);
696 if (!(b
->dmFields
& DM_DISPLAYFLAGS
)) b_interlaced
= FALSE
;
697 else b_interlaced
= !!(b
->dmDisplayFlags
& DM_INTERLACED
);
699 /* Interlaced in ascending order */
700 if ((ret
= a_interlaced
- b_interlaced
)) return ret
;
702 if (!(a
->dmFields
& DM_DISPLAYFIXEDOUTPUT
)) a_stretched
= FALSE
;
703 else a_stretched
= a
->dmDisplayFixedOutput
== DMDFO_STRETCH
;
704 if (!(b
->dmFields
& DM_DISPLAYFIXEDOUTPUT
)) b_stretched
= FALSE
;
705 else b_stretched
= b
->dmDisplayFixedOutput
== DMDFO_STRETCH
;
707 /* Stretched in ascending order */
708 if ((ret
= a_stretched
- b_stretched
)) return ret
;
713 static unsigned int query_reg_subkey_value( HKEY hkey
, const WCHAR
*name
, unsigned int name_size
,
714 KEY_VALUE_PARTIAL_INFORMATION
*value
, unsigned int size
)
718 if (!(subkey
= reg_open_key( hkey
, name
, name_size
))) return 0;
719 size
= query_reg_value( subkey
, NULL
, value
, size
);
724 static BOOL
read_display_adapter_settings( unsigned int index
, struct adapter
*info
)
727 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
728 WCHAR
*value_str
= (WCHAR
*)value
->Data
;
733 if (!enum_key
&& !(enum_key
= reg_open_key( NULL
, enum_keyW
, sizeof(enum_keyW
) )))
737 sprintf( buffer
, "\\Device\\Video%d", index
);
738 size
= query_reg_ascii_value( video_key
, buffer
, value
, sizeof(buffer
) );
739 if (!size
|| value
->Type
!= REG_SZ
||
740 value
->DataLength
<= sizeof("\\Registry\\Machine\\") * sizeof(WCHAR
))
744 memcpy( info
->dev
.device_key
, value_str
, value
->DataLength
);
745 info
->config_key
= info
->dev
.device_key
+ sizeof("\\Registry\\Machine\\") - 1;
747 if (!(hkey
= reg_open_key( NULL
, value_str
, value
->DataLength
- sizeof(WCHAR
) )))
751 if (query_reg_value( hkey
, driver_descW
, value
, sizeof(buffer
) ) && value
->Type
== REG_SZ
)
752 memcpy( info
->dev
.device_string
, value_str
, value
->DataLength
);
756 sprintf( buffer
, "\\\\.\\DISPLAY%d", index
+ 1 );
757 asciiz_to_unicode( info
->dev
.device_name
, buffer
);
759 if (!(hkey
= reg_open_key( config_key
, info
->config_key
,
760 lstrlenW( info
->config_key
) * sizeof(WCHAR
) )))
764 if (query_reg_value( hkey
, state_flagsW
, value
, sizeof(buffer
) ) && value
->Type
== REG_DWORD
)
765 info
->dev
.state_flags
= *(const DWORD
*)value
->Data
;
768 info
->dev
.interface_name
[0] = 0;
771 if (query_reg_value( hkey
, mode_countW
, value
, sizeof(buffer
) ) && value
->Type
== REG_DWORD
)
772 info
->mode_count
= *(const DWORD
*)value
->Data
;
774 /* Modes, allocate an extra mode for easier iteration */
775 if ((info
->modes
= calloc( info
->mode_count
+ 1, sizeof(DEVMODEW
) )))
777 for (i
= 0, mode
= info
->modes
; i
< info
->mode_count
; i
++)
779 mode
->dmSize
= offsetof(DEVMODEW
, dmICMMethod
);
780 if (!read_adapter_mode( hkey
, i
, mode
)) break;
781 mode
= NEXT_DEVMODEW(mode
);
783 info
->mode_count
= i
;
785 qsort(info
->modes
, info
->mode_count
, sizeof(*info
->modes
) + info
->modes
->dmDriverExtra
, mode_compare
);
789 size
= query_reg_value( hkey
, gpu_idW
, value
, sizeof(buffer
) );
791 if (!size
|| value
->Type
!= REG_SZ
|| !info
->mode_count
|| !info
->modes
) return FALSE
;
793 if (!(hkey
= reg_open_key( enum_key
, value_str
, value
->DataLength
- sizeof(WCHAR
) )))
796 size
= query_reg_subkey_value( hkey
, devpropkey_gpu_luidW
, sizeof(devpropkey_gpu_luidW
), value
, sizeof(buffer
) );
797 if (size
!= sizeof(info
->gpu_luid
))
802 memcpy( &info
->gpu_luid
, value
->Data
, sizeof(info
->gpu_luid
) );
804 size
= query_reg_value( hkey
, hardware_idW
, value
, sizeof(buffer
) );
806 if (!size
|| (value
->Type
!= REG_SZ
&& value
->Type
!= REG_MULTI_SZ
))
809 lstrcpyW( info
->dev
.device_id
, value_str
);
813 static BOOL
read_monitor_settings( struct adapter
*adapter
, UINT index
, struct monitor
*monitor
)
816 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
817 WCHAR
*device_name
, *value_str
= (WCHAR
*)value
->Data
, *ptr
;
821 monitor
->flags
= adapter
->id
? 0 : MONITORINFOF_PRIMARY
;
824 sprintf( buffer
, "\\\\.\\DISPLAY%d\\Monitor%d", adapter
->id
+ 1, index
);
825 asciiz_to_unicode( monitor
->dev
.device_name
, buffer
);
827 if (!(hkey
= reg_open_key( config_key
, adapter
->config_key
,
828 lstrlenW( adapter
->config_key
) * sizeof(WCHAR
) )))
832 sprintf( buffer
, "MonitorID%u", index
);
833 size
= query_reg_ascii_value( hkey
, buffer
, value
, sizeof(buffer
) );
835 if (!size
|| value
->Type
!= REG_SZ
) return FALSE
;
836 len
= asciiz_to_unicode( monitor
->dev
.interface_name
, "\\\\\?\\" ) / sizeof(WCHAR
) - 1;
837 memcpy( monitor
->dev
.interface_name
+ len
, value_str
, value
->DataLength
- sizeof(WCHAR
) );
838 len
+= value
->DataLength
/ sizeof(WCHAR
) - 1;
839 monitor
->dev
.interface_name
[len
++] = '#';
840 memcpy( monitor
->dev
.interface_name
+ len
, guid_devinterface_monitorW
,
841 sizeof(guid_devinterface_monitorW
) );
843 /* Replace '\\' with '#' after prefix */
844 for (ptr
= monitor
->dev
.interface_name
+ ARRAYSIZE("\\\\\?\\") - 1; *ptr
; ptr
++)
845 if (*ptr
== '\\') *ptr
= '#';
847 if (!(hkey
= reg_open_key( enum_key
, value_str
, value
->DataLength
- sizeof(WCHAR
) )))
850 /* StateFlags, WINE_DEVPROPKEY_MONITOR_STATEFLAGS */
851 size
= query_reg_subkey_value( hkey
, wine_devpropkey_monitor_stateflagsW
,
852 sizeof(wine_devpropkey_monitor_stateflagsW
),
853 value
, sizeof(buffer
) );
854 if (size
!= sizeof(monitor
->dev
.state_flags
))
859 monitor
->dev
.state_flags
= *(const DWORD
*)value
->Data
;
862 size
= query_reg_subkey_value( hkey
, devpropkey_monitor_output_idW
,
863 sizeof(devpropkey_monitor_output_idW
),
864 value
, sizeof(buffer
) );
865 if (size
!= sizeof(monitor
->output_id
))
870 monitor
->output_id
= *(const unsigned int *)value
->Data
;
872 /* rc_monitor, WINE_DEVPROPKEY_MONITOR_RCMONITOR */
873 size
= query_reg_subkey_value( hkey
, wine_devpropkey_monitor_rcmonitorW
,
874 sizeof(wine_devpropkey_monitor_rcmonitorW
),
875 value
, sizeof(buffer
) );
876 if (size
!= sizeof(monitor
->rc_monitor
))
881 monitor
->rc_monitor
= *(const RECT
*)value
->Data
;
883 /* rc_work, WINE_DEVPROPKEY_MONITOR_RCWORK */
884 size
= query_reg_subkey_value( hkey
, wine_devpropkey_monitor_rcworkW
,
885 sizeof(wine_devpropkey_monitor_rcworkW
),
886 value
, sizeof(buffer
) );
887 if (size
!= sizeof(monitor
->rc_work
))
892 monitor
->rc_work
= *(const RECT
*)value
->Data
;
895 if (!query_reg_value( hkey
, device_descW
, value
, sizeof(buffer
) ) || value
->Type
!= REG_SZ
)
900 memcpy( monitor
->dev
.device_string
, value
->Data
, value
->DataLength
);
903 if (!query_reg_value( hkey
, driverW
, value
, sizeof(buffer
) ) || value
->Type
!= REG_SZ
)
908 size
= asciiz_to_unicode( monitor
->dev
.device_key
,
909 "\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\" );
910 device_name
= &monitor
->dev
.device_key
[size
/ sizeof(WCHAR
) - 1];
911 memcpy( device_name
, value_str
, value
->DataLength
);
914 if (!query_reg_value( hkey
, hardware_idW
, value
, sizeof(buffer
) ) ||
915 (value
->Type
!= REG_SZ
&& value
->Type
!= REG_MULTI_SZ
))
920 size
= lstrlenW( value_str
);
921 memcpy( monitor
->dev
.device_id
, value_str
, size
* sizeof(WCHAR
) );
922 monitor
->dev
.device_id
[size
++] = '\\';
923 lstrcpyW( monitor
->dev
.device_id
+ size
, device_name
);
926 if ((subkey
= reg_open_key( hkey
, device_parametersW
, sizeof(device_parametersW
) )))
928 if (query_reg_value( subkey
, edidW
, value
, sizeof(buffer
) ))
929 get_monitor_info_from_edid( &monitor
->edid_info
, value
->Data
, value
->DataLength
);
937 static void reg_empty_key( HKEY root
, const char *key_name
)
940 KEY_NODE_INFORMATION
*key
= (KEY_NODE_INFORMATION
*)buffer
;
941 KEY_VALUE_FULL_INFORMATION
*value
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
947 hkey
= reg_open_key( root
, bufferW
, asciiz_to_unicode( bufferW
, key_name
) - sizeof(WCHAR
) );
951 while (!NtEnumerateKey( hkey
, 0, KeyNodeInformation
, key
, sizeof(buffer
), &size
))
952 reg_delete_tree( hkey
, key
->Name
, key
->NameLength
);
954 while (!NtEnumerateValueKey( hkey
, 0, KeyValueFullInformation
, value
, sizeof(buffer
), &size
))
956 UNICODE_STRING name
= { value
->NameLength
, value
->NameLength
, value
->Name
};
957 NtDeleteValueKey( hkey
, &name
);
960 if (hkey
!= root
) NtClose( hkey
);
963 static void prepare_devices(void)
966 KEY_NODE_INFORMATION
*key
= (void *)buffer
;
967 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
968 WCHAR
*value_str
= (WCHAR
*)value
->Data
;
972 HKEY hkey
, subkey
, device_key
, prop_key
;
974 if (!enum_key
) enum_key
= reg_create_key( NULL
, enum_keyW
, sizeof(enum_keyW
), 0, NULL
);
975 if (!control_key
) control_key
= reg_create_key( NULL
, control_keyW
, sizeof(control_keyW
), 0, NULL
);
976 if (!video_key
) video_key
= reg_create_key( NULL
, devicemap_video_keyW
, sizeof(devicemap_video_keyW
),
977 REG_OPTION_VOLATILE
, NULL
);
979 /* delete monitors */
980 reg_empty_key( enum_key
, "DISPLAY" );
981 sprintf( buffer
, "Class\\%s", guid_devclass_monitorA
);
982 hkey
= reg_create_key( control_key
, bufferW
, asciiz_to_unicode( bufferW
, buffer
) - sizeof(WCHAR
),
984 reg_empty_key( hkey
, NULL
);
985 set_reg_value( hkey
, classW
, REG_SZ
, monitorW
, sizeof(monitorW
) );
988 /* delete adapters */
989 reg_empty_key( video_key
, NULL
);
992 sprintf( buffer
, "Class\\%s", guid_devclass_displayA
);
993 hkey
= reg_create_key( control_key
, bufferW
, asciiz_to_unicode( bufferW
, buffer
) - sizeof(WCHAR
),
995 reg_empty_key( hkey
, NULL
);
996 set_reg_value( hkey
, classW
, REG_SZ
, displayW
, sizeof(displayW
) );
999 hkey
= reg_open_key( enum_key
, pciW
, sizeof(pciW
) );
1001 /* To preserve GPU GUIDs, mark them as not present and delete them in cleanup_devices if needed. */
1002 while (!NtEnumerateKey( hkey
, i
++, KeyNodeInformation
, key
, sizeof(buffer
), &size
))
1006 if (!(subkey
= reg_open_key( hkey
, key
->Name
, key
->NameLength
))) continue;
1008 while (!NtEnumerateKey( subkey
, j
++, KeyNodeInformation
, key
, sizeof(buffer
), &size
))
1010 if (!(device_key
= reg_open_key( subkey
, key
->Name
, key
->NameLength
))) continue;
1011 size
= query_reg_value( device_key
, class_guidW
, value
, sizeof(buffer
) );
1012 if (size
!= sizeof(guid_devclass_displayW
) || wcscmp( value_str
, guid_devclass_displayW
))
1014 NtClose( device_key
);
1018 size
= query_reg_value( device_key
, class_guidW
, value
, sizeof(buffer
) );
1019 if (size
== sizeof(guid_devclass_displayW
) &&
1020 !wcscmp( (const WCHAR
*)value
->Data
, guid_devclass_displayW
) &&
1021 (prop_key
= reg_create_key( device_key
, devpropkey_device_ispresentW
,
1022 sizeof(devpropkey_device_ispresentW
), 0, NULL
)))
1024 BOOL present
= FALSE
;
1025 set_reg_value( prop_key
, NULL
, 0xffff0000 | DEVPROP_TYPE_BOOLEAN
,
1026 &present
, sizeof(present
) );
1027 NtClose( prop_key
);
1030 NtClose( device_key
);
1039 static void cleanup_devices(void)
1042 KEY_NODE_INFORMATION
*key
= (void *)buffer
;
1043 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
1044 WCHAR bufferW
[512], *value_str
= (WCHAR
*)value
->Data
;
1047 HKEY hkey
, subkey
, device_key
, prop_key
;
1049 hkey
= reg_open_key( enum_key
, pciW
, sizeof(pciW
) );
1051 while (!NtEnumerateKey( hkey
, i
++, KeyNodeInformation
, key
, sizeof(buffer
), &size
))
1055 if (!(subkey
= reg_open_key( hkey
, key
->Name
, key
->NameLength
))) continue;
1057 while (!NtEnumerateKey( subkey
, j
++, KeyNodeInformation
, key
, sizeof(buffer
), &size
))
1059 BOOL present
= FALSE
;
1061 if (!(device_key
= reg_open_key( subkey
, key
->Name
, key
->NameLength
))) continue;
1062 memcpy( bufferW
, key
->Name
, key
->NameLength
);
1063 bufferW
[key
->NameLength
/ sizeof(WCHAR
)] = 0;
1065 size
= query_reg_value( device_key
, class_guidW
, value
, sizeof(buffer
) );
1066 if (size
!= sizeof(guid_devclass_displayW
) || wcscmp( value_str
, guid_devclass_displayW
))
1068 NtClose( device_key
);
1072 if ((prop_key
= reg_open_key( device_key
, devpropkey_device_ispresentW
,
1073 sizeof(devpropkey_device_ispresentW
) )))
1075 if (query_reg_value( prop_key
, NULL
, value
, sizeof(buffer
) ) == sizeof(BOOL
))
1076 present
= *(const BOOL
*)value
->Data
;
1077 NtClose( prop_key
);
1080 NtClose( device_key
);
1082 if (!present
&& reg_delete_tree( subkey
, bufferW
, lstrlenW( bufferW
) * sizeof(WCHAR
) ))
1092 /* see UuidCreate */
1093 static void uuid_create( GUID
*uuid
)
1096 NtQuerySystemInformation( SystemInterruptInformation
, buf
, sizeof(buf
), NULL
);
1097 memcpy( uuid
, buf
, sizeof(*uuid
) );
1098 uuid
->Data3
&= 0x0fff;
1099 uuid
->Data3
|= (4 << 12);
1100 uuid
->Data4
[0] &= 0x3f;
1101 uuid
->Data4
[0] |= 0x80;
1104 #define TICKSPERSEC 10000000
1105 #define SECSPERDAY 86400
1106 #define DAYSPERQUADRICENTENNIUM (365 * 400 + 97)
1107 #define DAYSPERNORMALQUADRENNIUM (365 * 4 + 1)
1109 static unsigned int format_date( WCHAR
*bufferW
, LONGLONG time
)
1111 int cleaps
, years
, yearday
, months
, days
;
1112 unsigned int day
, month
, year
;
1115 days
= time
/ TICKSPERSEC
/ SECSPERDAY
;
1117 /* compute year, month and day of month, see RtlTimeToTimeFields */
1118 cleaps
= (3 * ((4 * days
+ 1227) / DAYSPERQUADRICENTENNIUM
) + 3) / 4;
1119 days
+= 28188 + cleaps
;
1120 years
= (20 * days
- 2442) / (5 * DAYSPERNORMALQUADRENNIUM
);
1121 yearday
= days
- (years
* DAYSPERNORMALQUADRENNIUM
) / 4;
1122 months
= (64 * yearday
) / 1959;
1126 year
= years
+ 1524;
1130 month
= months
- 13;
1131 year
= years
+ 1525;
1133 day
= yearday
- (1959 * months
) / 64 ;
1135 sprintf( buffer
, "%u-%u-%u", month
, day
, year
);
1136 return asciiz_to_unicode( bufferW
, buffer
);
1139 struct device_manager_ctx
1141 unsigned int gpu_count
;
1142 unsigned int adapter_count
;
1143 unsigned int video_count
;
1144 unsigned int monitor_count
;
1145 unsigned int output_count
;
1146 unsigned int mode_count
;
1152 /* for the virtual desktop settings */
1156 UINT primary_height
;
1159 static void link_device( const WCHAR
*instance
, const WCHAR
*class )
1161 unsigned int instance_len
= lstrlenW( instance
), len
;
1162 unsigned int class_len
= lstrlenW( class );
1163 WCHAR buffer
[MAX_PATH
], *ptr
;
1166 static const WCHAR symbolic_linkW
[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
1167 static const WCHAR hashW
[] = {'#'};
1169 len
= asciiz_to_unicode( buffer
, "DeviceClasses\\" ) / sizeof(WCHAR
) - 1;
1170 memcpy( buffer
+ len
, class, class_len
* sizeof(WCHAR
) );
1172 len
+= asciiz_to_unicode( buffer
+ len
, "\\##?#" ) / sizeof(WCHAR
) - 1;
1173 memcpy( buffer
+ len
, instance
, instance_len
* sizeof(WCHAR
) );
1174 for (ptr
= buffer
+ len
; *ptr
; ptr
++) if (*ptr
== '\\') *ptr
= '#';
1175 len
+= instance_len
;
1176 buffer
[len
++] = '#';
1177 memcpy( buffer
+ len
, class, class_len
* sizeof(WCHAR
) );
1179 hkey
= reg_create_key( control_key
, buffer
, len
* sizeof(WCHAR
), 0, NULL
);
1181 set_reg_value( hkey
, device_instanceW
, REG_SZ
, instance
, (instance_len
+ 1) * sizeof(WCHAR
) );
1183 subkey
= reg_create_key( hkey
, hashW
, sizeof(hashW
), REG_OPTION_VOLATILE
, NULL
);
1187 len
= asciiz_to_unicode( buffer
, "\\\\?\\" ) / sizeof(WCHAR
) - 1;
1188 memcpy( buffer
+ len
, instance
, (instance_len
+ 1) * sizeof(WCHAR
) );
1189 len
+= instance_len
;
1190 memcpy( buffer
+ len
, class, (class_len
+ 1) * sizeof(WCHAR
) );
1191 len
+= class_len
+ 1;
1192 for (ptr
= buffer
+ 4; *ptr
; ptr
++) if (*ptr
== '\\') *ptr
= '#';
1193 set_reg_value( hkey
, symbolic_linkW
, REG_SZ
, buffer
, len
* sizeof(WCHAR
) );
1195 if ((subkey
= reg_create_key( hkey
, controlW
, sizeof(controlW
), REG_OPTION_VOLATILE
, NULL
)))
1197 const DWORD linked
= 1;
1198 set_reg_value( subkey
, linkedW
, REG_DWORD
, &linked
, sizeof(linked
) );
1203 static void add_gpu( const struct gdi_gpu
*gpu
, void *param
)
1205 struct device_manager_ctx
*ctx
= param
;
1209 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
1210 unsigned int gpu_index
, size
;
1214 static const BOOL present
= TRUE
;
1215 static const WCHAR wine_adapterW
[] = {'W','i','n','e',' ','A','d','a','p','t','e','r',0};
1216 static const WCHAR video_idW
[] = {'V','i','d','e','o','I','D',0};
1217 static const WCHAR driver_date_dataW
[] =
1218 {'D','r','i','v','e','r','D','a','t','e','D','a','t','a',0};
1219 static const WCHAR adapter_stringW
[] =
1220 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n',
1221 '.','A','d','a','p','t','e','r','S','t','r','i','n','g',0};
1222 static const WCHAR bios_stringW
[] =
1223 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n','.',
1224 'B','i','o','s','S','t','r','i','n','g',0};
1225 static const WCHAR chip_typeW
[] =
1226 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n','.',
1227 'C','h','i','p','T','y','p','e',0};
1228 static const WCHAR dac_typeW
[] =
1229 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n','.',
1230 'D','a','c','T','y','p','e',0};
1231 static const WCHAR ramdacW
[] =
1232 {'I','n','t','e','r','g','r','a','t','e','d',' ','R','A','M','D','A','C',0};
1233 static const WCHAR driver_dateW
[] = {'D','r','i','v','e','r','D','a','t','e',0};
1234 static const WCHAR driver_versionW
[] =
1235 {'D','r','i','v','e','r','V','e','r','s','i','o','n',0};
1237 TRACE( "%s %04X %04X %08X %02X\n", debugstr_w(gpu
->name
),
1238 gpu
->vendor_id
, gpu
->device_id
, gpu
->subsys_id
, gpu
->revision_id
);
1240 gpu_index
= ctx
->gpu_count
++;
1241 ctx
->adapter_count
= 0;
1242 ctx
->monitor_count
= 0;
1243 ctx
->mode_count
= 0;
1245 if (!enum_key
&& !(enum_key
= reg_create_key( NULL
, enum_keyW
, sizeof(enum_keyW
), 0, NULL
)))
1250 ctx
->mutex
= get_display_device_init_mutex();
1251 pthread_mutex_lock( &display_lock
);
1255 sprintf( buffer
, "PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X\\%08X",
1256 gpu
->vendor_id
, gpu
->device_id
, gpu
->subsys_id
, gpu
->revision_id
, gpu_index
);
1257 size
= asciiz_to_unicode( ctx
->gpuid
, buffer
);
1258 if (!(hkey
= reg_create_key( enum_key
, ctx
->gpuid
, size
- sizeof(WCHAR
), 0, NULL
))) return;
1260 set_reg_value( hkey
, classW
, REG_SZ
, displayW
, sizeof(displayW
) );
1261 set_reg_value( hkey
, class_guidW
, REG_SZ
, guid_devclass_displayW
,
1262 sizeof(guid_devclass_displayW
) );
1263 sprintf( buffer
, "%s\\%04X", guid_devclass_displayA
, gpu_index
);
1264 set_reg_value( hkey
, driverW
, REG_SZ
, bufferW
, asciiz_to_unicode( bufferW
, buffer
));
1266 sprintf( buffer
, "PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X",
1267 gpu
->vendor_id
, gpu
->device_id
, gpu
->subsys_id
, gpu
->revision_id
);
1268 size
= asciiz_to_unicode( bufferW
, buffer
);
1269 bufferW
[size
/ sizeof(WCHAR
)] = 0; /* for REG_MULTI_SZ */
1270 set_reg_value( hkey
, hardware_idW
, REG_MULTI_SZ
, bufferW
, size
+ sizeof(WCHAR
) );
1272 if ((subkey
= reg_create_key( hkey
, devpkey_device_matching_device_id
,
1273 sizeof(devpkey_device_matching_device_id
), 0, NULL
)))
1275 if (gpu
->vendor_id
&& gpu
->device_id
)
1276 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_STRING
, bufferW
, size
);
1278 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_STRING
, bufferW
,
1279 asciiz_to_unicode( bufferW
, "ROOT\\BasicRender" ));
1283 if (gpu
->vendor_id
&& gpu
->device_id
)
1285 if ((subkey
= reg_create_key( hkey
, devpkey_device_bus_number
,
1286 sizeof(devpkey_device_bus_number
), 0, NULL
)))
1288 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_UINT32
,
1289 &gpu_index
, sizeof(gpu_index
) );
1294 if ((subkey
= reg_create_key( hkey
, devpkey_device_removal_policy
,
1295 sizeof(devpkey_device_removal_policy
), 0, NULL
)))
1297 unsigned int removal_policy
= CM_REMOVAL_POLICY_EXPECT_NO_REMOVAL
;
1299 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_UINT32
,
1300 &removal_policy
, sizeof(removal_policy
) );
1305 if (!desc
[0]) desc
= wine_adapterW
;
1306 set_reg_value( hkey
, device_descW
, REG_SZ
, desc
, (lstrlenW( desc
) + 1) * sizeof(WCHAR
) );
1308 if ((subkey
= reg_create_key( hkey
, device_parametersW
, sizeof(device_parametersW
), 0, NULL
)))
1310 if (!query_reg_value( subkey
, video_idW
, value
, sizeof(buffer
) ))
1313 uuid_create( &guid
);
1314 sprintf( buffer
, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
1315 (unsigned int)guid
.Data1
, guid
.Data2
, guid
.Data3
, guid
.Data4
[0], guid
.Data4
[1], guid
.Data4
[2],
1316 guid
.Data4
[3], guid
.Data4
[4], guid
.Data4
[5], guid
.Data4
[6], guid
.Data4
[7] );
1317 size
= asciiz_to_unicode( ctx
->gpu_guid
, buffer
);
1318 TRACE( "created guid %s\n", debugstr_w(ctx
->gpu_guid
) );
1319 set_reg_value( subkey
, video_idW
, REG_SZ
, ctx
->gpu_guid
, size
);
1323 memcpy( ctx
->gpu_guid
, value
->Data
, value
->DataLength
);
1324 TRACE( "got guid %s\n", debugstr_w(ctx
->gpu_guid
) );
1329 if ((subkey
= reg_create_key( hkey
, devpropkey_gpu_vulkan_uuidW
,
1330 sizeof(devpropkey_gpu_vulkan_uuidW
), 0, NULL
)))
1332 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_GUID
,
1333 &gpu
->vulkan_uuid
, sizeof(gpu
->vulkan_uuid
) );
1337 if ((subkey
= reg_create_key( hkey
, devpropkey_device_ispresentW
,
1338 sizeof(devpropkey_device_ispresentW
), 0, NULL
)))
1340 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_BOOLEAN
,
1341 &present
, sizeof(present
) );
1345 if ((subkey
= reg_create_key( hkey
, devpropkey_gpu_luidW
, sizeof(devpropkey_gpu_luidW
), 0, NULL
)))
1347 if (query_reg_value( subkey
, NULL
, value
, sizeof(buffer
) ) != sizeof(LUID
))
1349 NtAllocateLocallyUniqueId( &ctx
->gpu_luid
);
1350 TRACE("allocated luid %08x%08x\n", (int)ctx
->gpu_luid
.HighPart
, (int)ctx
->gpu_luid
.LowPart
);
1351 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_UINT64
,
1352 &ctx
->gpu_luid
, sizeof(ctx
->gpu_luid
) );
1356 memcpy( &ctx
->gpu_luid
, value
->Data
, sizeof(ctx
->gpu_luid
) );
1357 TRACE("got luid %08x%08x\n", (int)ctx
->gpu_luid
.HighPart
, (int)ctx
->gpu_luid
.LowPart
);
1364 sprintf( buffer
, "Class\\%s\\%04X", guid_devclass_displayA
, gpu_index
);
1365 hkey
= reg_create_key( control_key
, bufferW
,
1366 asciiz_to_unicode( bufferW
, buffer
) - sizeof(WCHAR
), 0, NULL
);
1368 NtQuerySystemTime( &ft
);
1369 set_reg_value( hkey
, driver_dateW
, REG_SZ
, bufferW
, format_date( bufferW
, ft
.QuadPart
));
1371 set_reg_value( hkey
, driver_date_dataW
, REG_BINARY
, &ft
, sizeof(ft
) );
1373 size
= (lstrlenW( desc
) + 1) * sizeof(WCHAR
);
1374 set_reg_value( hkey
, driver_descW
, REG_SZ
, desc
, size
);
1375 set_reg_value( hkey
, adapter_stringW
, REG_BINARY
, desc
, size
);
1376 set_reg_value( hkey
, bios_stringW
, REG_BINARY
, desc
, size
);
1377 set_reg_value( hkey
, chip_typeW
, REG_BINARY
, desc
, size
);
1378 set_reg_value( hkey
, dac_typeW
, REG_BINARY
, ramdacW
, sizeof(ramdacW
) );
1380 if (gpu
->vendor_id
&& gpu
->device_id
)
1382 /* The last seven digits are the driver number. */
1383 switch (gpu
->vendor_id
)
1387 sprintf( buffer
, "31.0.101.4576" );
1391 sprintf( buffer
, "31.0.14051.5006" );
1395 sprintf( buffer
, "31.0.15.3625" );
1397 /* Default value for any other vendor. */
1399 sprintf( buffer
, "31.0.10.1000" );
1402 set_reg_value( hkey
, driver_versionW
, REG_SZ
, bufferW
, asciiz_to_unicode( bufferW
, buffer
) );
1407 link_device( ctx
->gpuid
, guid_devinterface_display_adapterW
);
1408 link_device( ctx
->gpuid
, guid_display_device_arrivalW
);
1411 static void add_adapter( const struct gdi_adapter
*adapter
, void *param
)
1413 struct device_manager_ctx
*ctx
= param
;
1414 unsigned int adapter_index
, video_index
, len
;
1415 char name
[64], buffer
[MAX_PATH
];
1416 WCHAR nameW
[64], bufferW
[MAX_PATH
];
1421 if (ctx
->adapter_key
)
1423 NtClose( ctx
->adapter_key
);
1424 ctx
->adapter_key
= NULL
;
1427 adapter_index
= ctx
->adapter_count
++;
1428 video_index
= ctx
->video_count
++;
1429 ctx
->monitor_count
= 0;
1430 ctx
->mode_count
= 0;
1432 len
= asciiz_to_unicode( bufferW
, "\\Registry\\Machine\\System\\CurrentControlSet\\"
1433 "Control\\Video\\" ) / sizeof(WCHAR
) - 1;
1434 lstrcpyW( bufferW
+ len
, ctx
->gpu_guid
);
1435 len
+= lstrlenW( bufferW
+ len
);
1436 sprintf( buffer
, "\\%04x", adapter_index
);
1437 len
+= asciiz_to_unicode( bufferW
+ len
, buffer
) / sizeof(WCHAR
) - 1;
1438 hkey
= reg_create_key( NULL
, bufferW
, len
* sizeof(WCHAR
),
1439 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
, NULL
);
1440 if (!hkey
) hkey
= reg_create_key( NULL
, bufferW
, len
* sizeof(WCHAR
),
1441 REG_OPTION_VOLATILE
| REG_OPTION_OPEN_LINK
, NULL
);
1443 sprintf( name
, "\\Device\\Video%u", video_index
);
1444 asciiz_to_unicode( nameW
, name
);
1445 set_reg_value( video_key
, nameW
, REG_SZ
, bufferW
, (lstrlenW( bufferW
) + 1) * sizeof(WCHAR
) );
1449 sprintf( buffer
, "\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\"
1450 "%s\\%04X", guid_devclass_displayA
, ctx
->gpu_count
- 1 );
1451 len
= asciiz_to_unicode( bufferW
, buffer
) - sizeof(WCHAR
);
1452 set_reg_value( hkey
, symbolic_link_valueW
, REG_LINK
, bufferW
, len
);
1455 else ERR( "failed to create link key\n" );
1457 /* Following information is Wine specific, it doesn't really exist on Windows. */
1458 len
= asciiz_to_unicode( bufferW
, "System\\CurrentControlSet\\Control\\Video\\" )
1459 / sizeof(WCHAR
) - 1;
1460 lstrcpyW( bufferW
+ len
, ctx
->gpu_guid
);
1461 len
+= lstrlenW( bufferW
+ len
);
1462 sprintf( buffer
, "\\%04x", adapter_index
);
1463 len
+= asciiz_to_unicode( bufferW
+ len
, buffer
) / sizeof(WCHAR
) - 1;
1464 ctx
->adapter_key
= reg_create_key( config_key
, bufferW
, len
* sizeof(WCHAR
),
1465 REG_OPTION_VOLATILE
, NULL
);
1467 set_reg_value( ctx
->adapter_key
, gpu_idW
, REG_SZ
, ctx
->gpuid
,
1468 (lstrlenW( ctx
->gpuid
) + 1) * sizeof(WCHAR
) );
1469 set_reg_value( ctx
->adapter_key
, state_flagsW
, REG_DWORD
, &adapter
->state_flags
,
1470 sizeof(adapter
->state_flags
) );
1473 static void add_monitor( const struct gdi_monitor
*monitor
, void *param
)
1475 struct device_manager_ctx
*ctx
= param
;
1476 char buffer
[MAX_PATH
], instance
[64];
1477 unsigned int monitor_index
, output_index
;
1478 struct edid_monitor_info monitor_info
;
1479 char monitor_id_string
[16];
1480 WCHAR bufferW
[MAX_PATH
];
1484 monitor_index
= ctx
->monitor_count
++;
1485 output_index
= ctx
->output_count
++;
1487 TRACE( "%u %s %s\n", monitor_index
, wine_dbgstr_rect(&monitor
->rc_monitor
), wine_dbgstr_rect(&monitor
->rc_work
) );
1489 get_monitor_info_from_edid( &monitor_info
, monitor
->edid
, monitor
->edid_len
);
1490 if (monitor_info
.flags
& MONITOR_INFO_HAS_MONITOR_ID
)
1491 strcpy( monitor_id_string
, monitor_info
.monitor_id_string
);
1493 strcpy( monitor_id_string
, "Default_Monitor" );
1495 sprintf( buffer
, "MonitorID%u", monitor_index
);
1496 sprintf( instance
, "DISPLAY\\%s\\%04X&%04X", monitor_id_string
, ctx
->video_count
- 1, monitor_index
);
1497 set_reg_ascii_value( ctx
->adapter_key
, buffer
, instance
);
1499 hkey
= reg_create_key( enum_key
, bufferW
, asciiz_to_unicode( bufferW
, instance
) - sizeof(WCHAR
),
1503 link_device( bufferW
, guid_devinterface_monitorW
);
1505 asciiz_to_unicode( bufferW
, "Generic Non-PnP Monitor" );
1506 set_reg_value( hkey
, device_descW
, REG_SZ
, bufferW
, (lstrlenW( bufferW
) + 1) * sizeof(WCHAR
) );
1508 set_reg_value( hkey
, classW
, REG_SZ
, monitorW
, sizeof(monitorW
) );
1509 sprintf( buffer
, "%s\\%04X", guid_devclass_monitorA
, output_index
);
1510 set_reg_ascii_value( hkey
, "Driver", buffer
);
1511 set_reg_value( hkey
, class_guidW
, REG_SZ
, guid_devclass_monitorW
, sizeof(guid_devclass_monitorW
) );
1513 sprintf( buffer
, "MONITOR\\%s", monitor_id_string
);
1514 len
= asciiz_to_unicode( bufferW
, buffer
);
1515 bufferW
[len
/ sizeof(WCHAR
)] = 0;
1516 set_reg_value( hkey
, hardware_idW
, REG_MULTI_SZ
, bufferW
, len
+ sizeof(WCHAR
) );
1518 if ((subkey
= reg_create_key( hkey
, device_parametersW
, sizeof(device_parametersW
), 0, NULL
)))
1520 static const WCHAR bad_edidW
[] = {'B','A','D','_','E','D','I','D',0};
1522 if (monitor
->edid_len
)
1523 set_reg_value( subkey
, edidW
, REG_BINARY
, monitor
->edid
, monitor
->edid_len
);
1525 set_reg_value( subkey
, bad_edidW
, REG_BINARY
, NULL
, 0 );
1530 if ((subkey
= reg_create_key( hkey
, wine_devpropkey_monitor_stateflagsW
,
1531 sizeof(wine_devpropkey_monitor_stateflagsW
), 0, NULL
)))
1533 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_UINT32
, &monitor
->state_flags
,
1534 sizeof(monitor
->state_flags
) );
1538 /* WINE_DEVPROPKEY_MONITOR_RCMONITOR */
1539 if ((subkey
= reg_create_key( hkey
, wine_devpropkey_monitor_rcmonitorW
,
1540 sizeof(wine_devpropkey_monitor_rcmonitorW
), 0, NULL
)))
1542 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_BINARY
, &monitor
->rc_monitor
,
1543 sizeof(monitor
->rc_monitor
) );
1547 /* WINE_DEVPROPKEY_MONITOR_RCWORK */
1548 if ((subkey
= reg_create_key( hkey
, wine_devpropkey_monitor_rcworkW
,
1549 sizeof(wine_devpropkey_monitor_rcworkW
), 0, NULL
)))
1551 TRACE( "rc_work %s\n", wine_dbgstr_rect(&monitor
->rc_work
) );
1552 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_BINARY
, &monitor
->rc_work
,
1553 sizeof(monitor
->rc_work
) );
1557 /* WINE_DEVPROPKEY_MONITOR_ADAPTERNAME */
1558 if ((subkey
= reg_create_key( hkey
, wine_devpropkey_monitor_adapternameW
,
1559 sizeof(wine_devpropkey_monitor_adapternameW
), 0, NULL
)))
1561 sprintf( buffer
, "\\\\.\\DISPLAY%u", ctx
->video_count
);
1562 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_STRING
, bufferW
,
1563 asciiz_to_unicode( bufferW
, buffer
));
1567 /* DEVPROPKEY_MONITOR_GPU_LUID */
1568 if ((subkey
= reg_create_key( hkey
, devpropkey_monitor_gpu_luidW
,
1569 sizeof(devpropkey_monitor_gpu_luidW
), 0, NULL
)))
1571 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_INT64
,
1572 &ctx
->gpu_luid
, sizeof(ctx
->gpu_luid
) );
1576 /* DEVPROPKEY_MONITOR_OUTPUT_ID */
1577 if ((subkey
= reg_create_key( hkey
, devpropkey_monitor_output_idW
,
1578 sizeof(devpropkey_monitor_output_idW
), 0, NULL
)))
1580 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_UINT32
,
1581 &output_index
, sizeof(output_index
) );
1587 sprintf( buffer
, "Class\\%s\\%04X", guid_devclass_monitorA
, output_index
);
1588 hkey
= reg_create_key( control_key
, bufferW
,
1589 asciiz_to_unicode( bufferW
, buffer
) - sizeof(WCHAR
), 0, NULL
);
1590 if (hkey
) NtClose( hkey
);
1593 static void add_mode( const DEVMODEW
*mode
, BOOL current
, void *param
)
1595 struct device_manager_ctx
*ctx
= param
;
1596 DEVMODEW nopos_mode
;
1598 if (!ctx
->adapter_count
)
1600 static const struct gdi_adapter default_adapter
=
1602 .state_flags
= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
| DISPLAY_DEVICE_PRIMARY_DEVICE
| DISPLAY_DEVICE_VGA_COMPATIBLE
,
1604 TRACE( "adding default fake adapter\n" );
1605 add_adapter( &default_adapter
, ctx
);
1609 nopos_mode
.dmPosition
.x
= 0;
1610 nopos_mode
.dmPosition
.y
= 0;
1611 nopos_mode
.dmFields
&= ~DM_POSITION
;
1613 if (write_adapter_mode( ctx
->adapter_key
, ctx
->mode_count
, &nopos_mode
))
1616 set_reg_value( ctx
->adapter_key
, mode_countW
, REG_DWORD
, &ctx
->mode_count
, sizeof(ctx
->mode_count
) );
1619 if (!read_adapter_mode( ctx
->adapter_key
, ENUM_REGISTRY_SETTINGS
, &nopos_mode
))
1620 write_adapter_mode( ctx
->adapter_key
, ENUM_REGISTRY_SETTINGS
, mode
);
1621 write_adapter_mode( ctx
->adapter_key
, ENUM_CURRENT_SETTINGS
, mode
);
1626 static const struct gdi_device_manager device_manager
=
1634 static void reset_display_manager_ctx( struct device_manager_ctx
*ctx
)
1636 HANDLE mutex
= ctx
->mutex
;
1638 if (ctx
->adapter_key
)
1640 NtClose( ctx
->adapter_key
);
1641 last_query_display_time
= 0;
1643 if (ctx
->gpu_count
) cleanup_devices();
1645 memset( ctx
, 0, sizeof(*ctx
) );
1646 if ((ctx
->mutex
= mutex
)) prepare_devices();
1649 static void release_display_manager_ctx( struct device_manager_ctx
*ctx
)
1653 pthread_mutex_unlock( &display_lock
);
1654 release_display_device_init_mutex( ctx
->mutex
);
1657 reset_display_manager_ctx( ctx
);
1660 static void clear_display_devices(void)
1662 struct adapter
*adapter
;
1663 struct monitor
*monitor
;
1665 if (list_head( &monitors
) == &virtual_monitor
.entry
)
1667 list_init( &monitors
);
1671 while (!list_empty( &monitors
))
1673 monitor
= LIST_ENTRY( list_head( &monitors
), struct monitor
, entry
);
1674 adapter_release( monitor
->adapter
);
1675 list_remove( &monitor
->entry
);
1679 while (!list_empty( &adapters
))
1681 adapter
= LIST_ENTRY( list_head( &adapters
), struct adapter
, entry
);
1682 list_remove( &adapter
->entry
);
1683 adapter_release( adapter
);
1687 static BOOL
update_display_cache_from_registry(void)
1689 DWORD adapter_id
, monitor_id
, monitor_count
= 0, size
;
1690 KEY_BASIC_INFORMATION key
;
1691 struct adapter
*adapter
;
1692 struct monitor
*monitor
, *monitor2
;
1693 HANDLE mutex
= NULL
;
1697 /* If user driver did initialize the registry, then exit */
1698 if (!video_key
&& !(video_key
= reg_open_key( NULL
, devicemap_video_keyW
,
1699 sizeof(devicemap_video_keyW
) )))
1702 status
= NtQueryKey( video_key
, KeyBasicInformation
, &key
,
1703 offsetof(KEY_BASIC_INFORMATION
, Name
), &size
);
1704 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
)
1707 if (key
.LastWriteTime
.QuadPart
<= last_query_display_time
) return TRUE
;
1709 mutex
= get_display_device_init_mutex();
1710 pthread_mutex_lock( &display_lock
);
1712 clear_display_devices();
1714 for (adapter_id
= 0;; adapter_id
++)
1716 if (!(adapter
= calloc( 1, sizeof(*adapter
) ))) break;
1717 adapter
->refcount
= 1;
1718 adapter
->id
= adapter_id
;
1720 if (!read_display_adapter_settings( adapter_id
, adapter
))
1722 adapter_release( adapter
);
1726 list_add_tail( &adapters
, &adapter
->entry
);
1727 for (monitor_id
= 0;; monitor_id
++)
1729 if (!(monitor
= calloc( 1, sizeof(*monitor
) ))) break;
1730 if (!read_monitor_settings( adapter
, monitor_id
, monitor
))
1736 monitor
->id
= monitor_id
;
1737 monitor
->adapter
= adapter_acquire( adapter
);
1739 LIST_FOR_EACH_ENTRY(monitor2
, &monitors
, struct monitor
, entry
)
1741 if (EqualRect(&monitor2
->rc_monitor
, &monitor
->rc_monitor
))
1743 monitor
->is_clone
= TRUE
;
1748 monitor
->handle
= UlongToHandle( ++monitor_count
);
1749 list_add_tail( &monitors
, &monitor
->entry
);
1753 if ((ret
= !list_empty( &adapters
) && !list_empty( &monitors
)))
1754 last_query_display_time
= key
.LastWriteTime
.QuadPart
;
1755 pthread_mutex_unlock( &display_lock
);
1756 release_display_device_init_mutex( mutex
);
1760 static BOOL
is_same_devmode( const DEVMODEW
*a
, const DEVMODEW
*b
)
1762 return a
->dmDisplayOrientation
== b
->dmDisplayOrientation
&&
1763 a
->dmBitsPerPel
== b
->dmBitsPerPel
&&
1764 a
->dmPelsWidth
== b
->dmPelsWidth
&&
1765 a
->dmPelsHeight
== b
->dmPelsHeight
&&
1766 a
->dmDisplayFrequency
== b
->dmDisplayFrequency
;
1769 static BOOL
default_update_display_devices( const struct gdi_device_manager
*manager
, BOOL force
, struct device_manager_ctx
*ctx
)
1771 /* default implementation: expose an adapter and a monitor with a few standard modes,
1772 * and read / write current display settings from / to the registry.
1774 static const DEVMODEW modes
[] =
1776 { .dmFields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
,
1777 .dmBitsPerPel
= 32, .dmPelsWidth
= 640, .dmPelsHeight
= 480, .dmDisplayFrequency
= 60, },
1778 { .dmFields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
,
1779 .dmBitsPerPel
= 32, .dmPelsWidth
= 800, .dmPelsHeight
= 600, .dmDisplayFrequency
= 60, },
1780 { .dmFields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
,
1781 .dmBitsPerPel
= 32, .dmPelsWidth
= 1024, .dmPelsHeight
= 768, .dmDisplayFrequency
= 60, },
1782 { .dmFields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
,
1783 .dmBitsPerPel
= 16, .dmPelsWidth
= 640, .dmPelsHeight
= 480, .dmDisplayFrequency
= 60, },
1784 { .dmFields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
,
1785 .dmBitsPerPel
= 16, .dmPelsWidth
= 800, .dmPelsHeight
= 600, .dmDisplayFrequency
= 60, },
1786 { .dmFields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
,
1787 .dmBitsPerPel
= 16, .dmPelsWidth
= 1024, .dmPelsHeight
= 768, .dmDisplayFrequency
= 60, },
1789 static const struct gdi_gpu gpu
;
1790 static const struct gdi_adapter adapter
=
1792 .state_flags
= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
| DISPLAY_DEVICE_PRIMARY_DEVICE
| DISPLAY_DEVICE_VGA_COMPATIBLE
,
1794 struct gdi_monitor monitor
=
1796 .state_flags
= DISPLAY_DEVICE_ACTIVE
| DISPLAY_DEVICE_ATTACHED
,
1798 DEVMODEW mode
= {{0}};
1801 if (!force
) return TRUE
;
1803 manager
->add_gpu( &gpu
, ctx
);
1804 manager
->add_adapter( &adapter
, ctx
);
1806 if (!read_adapter_mode( ctx
->adapter_key
, ENUM_CURRENT_SETTINGS
, &mode
))
1809 mode
.dmFields
|= DM_POSITION
;
1811 monitor
.rc_monitor
.right
= mode
.dmPelsWidth
;
1812 monitor
.rc_monitor
.bottom
= mode
.dmPelsHeight
;
1813 monitor
.rc_work
.right
= mode
.dmPelsWidth
;
1814 monitor
.rc_work
.bottom
= mode
.dmPelsHeight
;
1816 manager
->add_monitor( &monitor
, ctx
);
1817 for (i
= 0; i
< ARRAY_SIZE(modes
); ++i
)
1819 if (is_same_devmode( modes
+ i
, &mode
)) manager
->add_mode( &mode
, TRUE
, ctx
);
1820 else manager
->add_mode( modes
+ i
, FALSE
, ctx
);
1826 static BOOL
update_display_devices( const struct gdi_device_manager
*manager
, BOOL force
, struct device_manager_ctx
*ctx
)
1828 if (user_driver
->pUpdateDisplayDevices( manager
, force
, ctx
)) return TRUE
;
1829 return default_update_display_devices( manager
, force
, ctx
);
1832 /* parse the desktop size specification */
1833 static BOOL
parse_size( const WCHAR
*size
, unsigned int *width
, unsigned int *height
)
1837 *width
= wcstoul( size
, &end
, 10 );
1838 if (end
== size
) return FALSE
;
1839 if (*end
!= 'x') return FALSE
;
1841 *height
= wcstoul( size
, &end
, 10 );
1845 /* retrieve the default desktop size from the registry */
1846 static BOOL
get_default_desktop_size( unsigned int *width
, unsigned int *height
)
1848 static const WCHAR defaultW
[] = {'D','e','f','a','u','l','t',0};
1850 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
1854 /* @@ Wine registry key: HKCU\Software\Wine\Explorer\Desktops */
1855 if (!(hkey
= reg_open_hkcu_key( "Software\\Wine\\Explorer\\Desktops" ))) return FALSE
;
1857 size
= query_reg_value( hkey
, defaultW
, value
, sizeof(buffer
) );
1859 if (!size
|| value
->Type
!= REG_SZ
) return FALSE
;
1861 if (!parse_size( (const WCHAR
*)value
->Data
, width
, height
)) return FALSE
;
1865 static void desktop_add_gpu( const struct gdi_gpu
*gpu
, void *param
)
1869 static void desktop_add_adapter( const struct gdi_adapter
*adapter
, void *param
)
1871 struct device_manager_ctx
*ctx
= param
;
1872 ctx
->is_primary
= !!(adapter
->state_flags
& DISPLAY_DEVICE_PRIMARY_DEVICE
);
1875 static void desktop_add_monitor( const struct gdi_monitor
*monitor
, void *param
)
1879 static void desktop_add_mode( const DEVMODEW
*mode
, BOOL current
, void *param
)
1881 struct device_manager_ctx
*ctx
= param
;
1883 if (ctx
->is_primary
&& current
)
1885 ctx
->primary_bpp
= mode
->dmBitsPerPel
;
1886 ctx
->primary_width
= mode
->dmPelsWidth
;
1887 ctx
->primary_height
= mode
->dmPelsHeight
;
1891 static const struct gdi_device_manager desktop_device_manager
=
1894 desktop_add_adapter
,
1895 desktop_add_monitor
,
1899 static BOOL
desktop_update_display_devices( BOOL force
, struct device_manager_ctx
*ctx
)
1901 static const struct gdi_gpu gpu
;
1902 static const struct gdi_adapter adapter
=
1904 .state_flags
= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
| DISPLAY_DEVICE_PRIMARY_DEVICE
| DISPLAY_DEVICE_VGA_COMPATIBLE
,
1906 struct gdi_monitor monitor
=
1908 .state_flags
= DISPLAY_DEVICE_ACTIVE
| DISPLAY_DEVICE_ATTACHED
,
1910 static struct screen_size
1913 unsigned int height
;
1914 } screen_sizes
[] = {
1948 struct device_manager_ctx desktop_ctx
= {0};
1949 UINT screen_width
, screen_height
, max_width
, max_height
;
1950 unsigned int depths
[] = {8, 16, 0};
1951 DEVMODEW current
, mode
=
1953 .dmFields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
,
1954 .dmDisplayFrequency
= 60,
1958 if (!force
) return TRUE
;
1959 /* in virtual desktop mode, read the device list from the user driver but expose virtual devices */
1960 if (!update_display_devices( &desktop_device_manager
, TRUE
, &desktop_ctx
)) return FALSE
;
1962 max_width
= desktop_ctx
.primary_width
;
1963 max_height
= desktop_ctx
.primary_height
;
1964 depths
[ARRAY_SIZE(depths
) - 1] = desktop_ctx
.primary_bpp
;
1966 if (!get_default_desktop_size( &screen_width
, &screen_height
))
1968 screen_width
= max_width
;
1969 screen_height
= max_height
;
1972 add_gpu( &gpu
, ctx
);
1973 add_adapter( &adapter
, ctx
);
1974 if (!read_adapter_mode( ctx
->adapter_key
, ENUM_CURRENT_SETTINGS
, ¤t
))
1977 current
.dmFields
|= DM_POSITION
;
1978 current
.dmBitsPerPel
= desktop_ctx
.primary_bpp
;
1979 current
.dmPelsWidth
= screen_width
;
1980 current
.dmPelsHeight
= screen_height
;
1983 monitor
.rc_monitor
.right
= current
.dmPelsWidth
;
1984 monitor
.rc_monitor
.bottom
= current
.dmPelsHeight
;
1985 monitor
.rc_work
.right
= current
.dmPelsWidth
;
1986 monitor
.rc_work
.bottom
= current
.dmPelsHeight
;
1987 add_monitor( &monitor
, ctx
);
1989 for (i
= 0; i
< ARRAY_SIZE(depths
); ++i
)
1991 mode
.dmBitsPerPel
= depths
[i
];
1993 for (j
= 0; j
< ARRAY_SIZE(screen_sizes
); ++j
)
1995 mode
.dmPelsWidth
= screen_sizes
[j
].width
;
1996 mode
.dmPelsHeight
= screen_sizes
[j
].height
;
1998 if (mode
.dmPelsWidth
> max_width
|| mode
.dmPelsHeight
> max_height
) continue;
1999 if (mode
.dmPelsWidth
== max_width
&& mode
.dmPelsHeight
== max_height
) continue;
2000 if (mode
.dmPelsWidth
== screen_width
&& mode
.dmPelsHeight
== screen_height
) continue;
2002 if (is_same_devmode( &mode
, ¤t
)) add_mode( ¤t
, TRUE
, ctx
);
2003 else add_mode( &mode
, FALSE
, ctx
);
2006 mode
.dmPelsWidth
= screen_width
;
2007 mode
.dmPelsHeight
= screen_height
;
2008 if (is_same_devmode( &mode
, ¤t
)) add_mode( ¤t
, TRUE
, ctx
);
2009 else add_mode( &mode
, FALSE
, ctx
);
2011 if (max_width
!= screen_width
|| max_height
!= screen_height
)
2013 mode
.dmPelsWidth
= max_width
;
2014 mode
.dmPelsHeight
= max_height
;
2015 if (is_same_devmode( &mode
, ¤t
)) add_mode( ¤t
, TRUE
, ctx
);
2016 else add_mode( &mode
, FALSE
, ctx
);
2023 BOOL
update_display_cache( BOOL force
)
2025 static const WCHAR wine_service_station_name
[] =
2026 {'_','_','w','i','n','e','s','e','r','v','i','c','e','_','w','i','n','s','t','a','t','i','o','n',0};
2027 HWINSTA winstation
= NtUserGetProcessWindowStation();
2028 struct device_manager_ctx ctx
= {0};
2029 BOOL was_virtual_desktop
, ret
;
2030 WCHAR name
[MAX_PATH
];
2032 /* services do not have any adapters, only a virtual monitor */
2033 if (NtUserGetObjectInformation( winstation
, UOI_NAME
, name
, sizeof(name
), NULL
)
2034 && !wcscmp( name
, wine_service_station_name
))
2036 pthread_mutex_lock( &display_lock
);
2037 clear_display_devices();
2038 list_add_tail( &monitors
, &virtual_monitor
.entry
);
2039 pthread_mutex_unlock( &display_lock
);
2043 if ((was_virtual_desktop
= is_virtual_desktop())) ret
= TRUE
;
2044 else ret
= update_display_devices( &device_manager
, force
, &ctx
);
2046 /* as update_display_devices calls the user driver, it starts explorer and may change the virtual desktop state */
2047 if (ret
&& is_virtual_desktop())
2049 reset_display_manager_ctx( &ctx
);
2050 ret
= desktop_update_display_devices( force
|| !was_virtual_desktop
, &ctx
);
2053 release_display_manager_ctx( &ctx
);
2054 if (!ret
) WARN( "Failed to update display devices\n" );
2056 if (!update_display_cache_from_registry())
2060 ERR( "Failed to read display config.\n" );
2066 ERR( "Driver reported devices, but we failed to read them.\n" );
2070 return update_display_cache( TRUE
);
2076 static BOOL
lock_display_devices(void)
2078 if (!update_display_cache( FALSE
)) return FALSE
;
2079 pthread_mutex_lock( &display_lock
);
2083 static void unlock_display_devices(void)
2085 pthread_mutex_unlock( &display_lock
);
2088 static HDC
get_display_dc(void)
2090 pthread_mutex_lock( &display_dc_lock
);
2095 pthread_mutex_unlock( &display_dc_lock
);
2096 dc
= NtGdiOpenDCW( NULL
, NULL
, NULL
, 0, TRUE
, NULL
, NULL
, NULL
);
2097 pthread_mutex_lock( &display_dc_lock
);
2099 NtGdiDeleteObjectApp( dc
);
2106 static void release_display_dc( HDC hdc
)
2108 pthread_mutex_unlock( &display_dc_lock
);
2111 /**********************************************************************
2114 UINT
get_monitor_dpi( HMONITOR monitor
)
2116 /* FIXME: use the monitor DPI instead */
2120 /**********************************************************************
2121 * get_win_monitor_dpi
2123 UINT
get_win_monitor_dpi( HWND hwnd
)
2125 /* FIXME: use the monitor DPI instead */
2129 /**********************************************************************
2130 * get_thread_dpi_awareness
2132 DPI_AWARENESS
get_thread_dpi_awareness(void)
2134 struct ntuser_thread_info
*info
= NtUserGetThreadInfo();
2135 ULONG_PTR context
= info
->dpi_awareness
;
2137 if (!context
) context
= NtUserGetProcessDpiAwarenessContext( NULL
);
2148 case (ULONG_PTR
)DPI_AWARENESS_CONTEXT_UNAWARE
:
2149 case (ULONG_PTR
)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE
:
2150 case (ULONG_PTR
)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
:
2153 return DPI_AWARENESS_INVALID
;
2157 DWORD
get_process_layout(void)
2159 return process_layout
== ~0u ? 0 : process_layout
;
2162 /**********************************************************************
2165 UINT
get_thread_dpi(void)
2167 switch (get_thread_dpi_awareness())
2169 case DPI_AWARENESS_UNAWARE
: return USER_DEFAULT_SCREEN_DPI
;
2170 case DPI_AWARENESS_SYSTEM_AWARE
: return system_dpi
;
2171 default: return 0; /* no scaling */
2175 /* see GetDpiForSystem */
2176 UINT
get_system_dpi(void)
2178 if (get_thread_dpi_awareness() == DPI_AWARENESS_UNAWARE
) return USER_DEFAULT_SCREEN_DPI
;
2182 /* see GetAwarenessFromDpiAwarenessContext */
2183 static DPI_AWARENESS
get_awareness_from_dpi_awareness_context( DPI_AWARENESS_CONTEXT context
)
2185 switch ((ULONG_PTR
)context
)
2193 return (ULONG_PTR
)context
& 3;
2194 case (ULONG_PTR
)DPI_AWARENESS_CONTEXT_UNAWARE
:
2195 case (ULONG_PTR
)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE
:
2196 case (ULONG_PTR
)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
:
2197 return ~(ULONG_PTR
)context
;
2199 return DPI_AWARENESS_INVALID
;
2203 /**********************************************************************
2204 * SetThreadDpiAwarenessContext (win32u.so)
2206 DPI_AWARENESS_CONTEXT WINAPI
SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT context
)
2208 struct ntuser_thread_info
*info
= NtUserGetThreadInfo();
2209 DPI_AWARENESS prev
, val
= get_awareness_from_dpi_awareness_context( context
);
2211 if (val
== DPI_AWARENESS_INVALID
)
2213 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
2216 if (!(prev
= info
->dpi_awareness
))
2218 prev
= NtUserGetProcessDpiAwarenessContext( GetCurrentProcess() ) & 3;
2219 prev
|= 0x80000010; /* restore to process default */
2221 if (((ULONG_PTR
)context
& ~(ULONG_PTR
)0x13) == 0x80000000) info
->dpi_awareness
= 0;
2222 else info
->dpi_awareness
= val
| 0x10;
2223 return ULongToHandle( prev
);
2226 /**********************************************************************
2229 RECT
map_dpi_rect( RECT rect
, UINT dpi_from
, UINT dpi_to
)
2231 if (dpi_from
&& dpi_to
&& dpi_from
!= dpi_to
)
2233 rect
.left
= muldiv( rect
.left
, dpi_to
, dpi_from
);
2234 rect
.top
= muldiv( rect
.top
, dpi_to
, dpi_from
);
2235 rect
.right
= muldiv( rect
.right
, dpi_to
, dpi_from
);
2236 rect
.bottom
= muldiv( rect
.bottom
, dpi_to
, dpi_from
);
2241 /**********************************************************************
2244 POINT
map_dpi_point( POINT pt
, UINT dpi_from
, UINT dpi_to
)
2246 if (dpi_from
&& dpi_to
&& dpi_from
!= dpi_to
)
2248 pt
.x
= muldiv( pt
.x
, dpi_to
, dpi_from
);
2249 pt
.y
= muldiv( pt
.y
, dpi_to
, dpi_from
);
2254 /**********************************************************************
2255 * point_win_to_phys_dpi
2257 static POINT
point_win_to_phys_dpi( HWND hwnd
, POINT pt
)
2259 return map_dpi_point( pt
, get_dpi_for_window( hwnd
), get_win_monitor_dpi( hwnd
) );
2262 /**********************************************************************
2263 * point_phys_to_win_dpi
2265 POINT
point_phys_to_win_dpi( HWND hwnd
, POINT pt
)
2267 return map_dpi_point( pt
, get_win_monitor_dpi( hwnd
), get_dpi_for_window( hwnd
));
2270 /**********************************************************************
2271 * point_thread_to_win_dpi
2273 POINT
point_thread_to_win_dpi( HWND hwnd
, POINT pt
)
2275 UINT dpi
= get_thread_dpi();
2276 if (!dpi
) dpi
= get_win_monitor_dpi( hwnd
);
2277 return map_dpi_point( pt
, dpi
, get_dpi_for_window( hwnd
));
2280 /**********************************************************************
2281 * rect_thread_to_win_dpi
2283 RECT
rect_thread_to_win_dpi( HWND hwnd
, RECT rect
)
2285 UINT dpi
= get_thread_dpi();
2286 if (!dpi
) dpi
= get_win_monitor_dpi( hwnd
);
2287 return map_dpi_rect( rect
, dpi
, get_dpi_for_window( hwnd
) );
2290 /* map value from system dpi to standard 96 dpi for storing in the registry */
2291 static int map_from_system_dpi( int val
)
2293 return muldiv( val
, USER_DEFAULT_SCREEN_DPI
, get_system_dpi() );
2296 /* map value from 96 dpi to system or custom dpi */
2297 static int map_to_dpi( int val
, UINT dpi
)
2299 if (!dpi
) dpi
= get_system_dpi();
2300 return muldiv( val
, dpi
, USER_DEFAULT_SCREEN_DPI
);
2303 RECT
get_virtual_screen_rect( UINT dpi
)
2305 struct monitor
*monitor
;
2308 if (!lock_display_devices()) return rect
;
2310 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
2312 union_rect( &rect
, &rect
, &monitor
->rc_monitor
);
2315 unlock_display_devices();
2317 if (dpi
) rect
= map_dpi_rect( rect
, system_dpi
, dpi
);
2321 static BOOL
is_window_rect_full_screen( const RECT
*rect
)
2323 struct monitor
*monitor
;
2326 if (!lock_display_devices()) return FALSE
;
2328 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
2330 if (!(monitor
->dev
.state_flags
& DISPLAY_DEVICE_ACTIVE
))
2333 if (rect
->left
<= monitor
->rc_monitor
.left
&& rect
->right
>= monitor
->rc_monitor
.right
&&
2334 rect
->top
<= monitor
->rc_monitor
.top
&& rect
->bottom
>= monitor
->rc_monitor
.bottom
)
2341 unlock_display_devices();
2345 RECT
get_display_rect( const WCHAR
*display
)
2347 struct monitor
*monitor
;
2350 if (!lock_display_devices()) return rect
;
2352 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
2354 if (!monitor
->adapter
|| wcsicmp( monitor
->adapter
->dev
.device_name
, display
)) continue;
2355 rect
= monitor
->rc_monitor
;
2359 unlock_display_devices();
2360 return map_dpi_rect( rect
, system_dpi
, get_thread_dpi() );
2363 RECT
get_primary_monitor_rect( UINT dpi
)
2365 struct monitor
*monitor
;
2368 if (!lock_display_devices()) return rect
;
2370 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
2372 if (!(monitor
->flags
& MONITORINFOF_PRIMARY
)) continue;
2373 rect
= monitor
->rc_monitor
;
2377 unlock_display_devices();
2378 return map_dpi_rect( rect
, system_dpi
, dpi
);
2381 /**********************************************************************
2382 * NtUserGetDisplayConfigBufferSizes (win32u.@)
2384 LONG WINAPI
NtUserGetDisplayConfigBufferSizes( UINT32 flags
, UINT32
*num_path_info
,
2385 UINT32
*num_mode_info
)
2387 struct monitor
*monitor
;
2390 TRACE( "(0x%x %p %p)\n", flags
, num_path_info
, num_mode_info
);
2392 if (!num_path_info
|| !num_mode_info
)
2393 return ERROR_INVALID_PARAMETER
;
2400 case QDC_ONLY_ACTIVE_PATHS
:
2401 case QDC_DATABASE_CURRENT
:
2404 return ERROR_INVALID_PARAMETER
;
2407 /* FIXME: semi-stub */
2408 if (flags
!= QDC_ONLY_ACTIVE_PATHS
)
2409 FIXME( "only returning active paths\n" );
2411 if (lock_display_devices())
2413 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
2415 if (!(monitor
->dev
.state_flags
& DISPLAY_DEVICE_ACTIVE
))
2419 unlock_display_devices();
2422 *num_path_info
= count
;
2423 *num_mode_info
= count
* 2;
2424 TRACE( "returning %u paths %u modes\n", *num_path_info
, *num_mode_info
);
2425 return ERROR_SUCCESS
;
2428 static DISPLAYCONFIG_ROTATION
get_dc_rotation( const DEVMODEW
*devmode
)
2430 if (devmode
->dmFields
& DM_DISPLAYORIENTATION
)
2431 return devmode
->dmDisplayOrientation
+ 1;
2433 return DISPLAYCONFIG_ROTATION_IDENTITY
;
2436 static DISPLAYCONFIG_SCANLINE_ORDERING
get_dc_scanline_ordering( const DEVMODEW
*devmode
)
2438 if (!(devmode
->dmFields
& DM_DISPLAYFLAGS
))
2439 return DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED
;
2440 else if (devmode
->dmDisplayFlags
& DM_INTERLACED
)
2441 return DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED
;
2443 return DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE
;
2446 static DISPLAYCONFIG_PIXELFORMAT
get_dc_pixelformat( DWORD dmBitsPerPel
)
2448 if ((dmBitsPerPel
== 8) || (dmBitsPerPel
== 16) ||
2449 (dmBitsPerPel
== 24) || (dmBitsPerPel
== 32))
2450 return dmBitsPerPel
/ 8;
2452 return DISPLAYCONFIG_PIXELFORMAT_NONGDI
;
2455 static void set_mode_target_info( DISPLAYCONFIG_MODE_INFO
*info
, const LUID
*gpu_luid
, UINT32 target_id
,
2456 UINT32 flags
, const DEVMODEW
*devmode
)
2458 DISPLAYCONFIG_TARGET_MODE
*mode
= &info
->targetMode
;
2460 info
->infoType
= DISPLAYCONFIG_MODE_INFO_TYPE_TARGET
;
2461 info
->adapterId
= *gpu_luid
;
2462 info
->id
= target_id
;
2464 /* FIXME: Populate pixelRate/hSyncFreq/totalSize with real data */
2465 mode
->targetVideoSignalInfo
.pixelRate
= devmode
->dmDisplayFrequency
* devmode
->dmPelsWidth
* devmode
->dmPelsHeight
;
2466 mode
->targetVideoSignalInfo
.hSyncFreq
.Numerator
= devmode
->dmDisplayFrequency
* devmode
->dmPelsWidth
;
2467 mode
->targetVideoSignalInfo
.hSyncFreq
.Denominator
= 1;
2468 mode
->targetVideoSignalInfo
.vSyncFreq
.Numerator
= devmode
->dmDisplayFrequency
;
2469 mode
->targetVideoSignalInfo
.vSyncFreq
.Denominator
= 1;
2470 mode
->targetVideoSignalInfo
.activeSize
.cx
= devmode
->dmPelsWidth
;
2471 mode
->targetVideoSignalInfo
.activeSize
.cy
= devmode
->dmPelsHeight
;
2472 if (flags
& QDC_DATABASE_CURRENT
)
2474 mode
->targetVideoSignalInfo
.totalSize
.cx
= 0;
2475 mode
->targetVideoSignalInfo
.totalSize
.cy
= 0;
2479 mode
->targetVideoSignalInfo
.totalSize
.cx
= devmode
->dmPelsWidth
;
2480 mode
->targetVideoSignalInfo
.totalSize
.cy
= devmode
->dmPelsHeight
;
2482 mode
->targetVideoSignalInfo
.videoStandard
= D3DKMDT_VSS_OTHER
;
2483 mode
->targetVideoSignalInfo
.scanLineOrdering
= get_dc_scanline_ordering( devmode
);
2486 static void set_path_target_info( DISPLAYCONFIG_PATH_TARGET_INFO
*info
, const LUID
*gpu_luid
,
2487 UINT32 target_id
, UINT32 mode_index
, const DEVMODEW
*devmode
)
2489 info
->adapterId
= *gpu_luid
;
2490 info
->id
= target_id
;
2491 info
->modeInfoIdx
= mode_index
;
2492 info
->outputTechnology
= DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL
;
2493 info
->rotation
= get_dc_rotation( devmode
);
2494 info
->scaling
= DISPLAYCONFIG_SCALING_IDENTITY
;
2495 info
->refreshRate
.Numerator
= devmode
->dmDisplayFrequency
;
2496 info
->refreshRate
.Denominator
= 1;
2497 info
->scanLineOrdering
= get_dc_scanline_ordering( devmode
);
2498 info
->targetAvailable
= TRUE
;
2499 info
->statusFlags
= DISPLAYCONFIG_TARGET_IN_USE
;
2502 static void set_mode_source_info( DISPLAYCONFIG_MODE_INFO
*info
, const LUID
*gpu_luid
,
2503 UINT32 source_id
, const DEVMODEW
*devmode
)
2505 DISPLAYCONFIG_SOURCE_MODE
*mode
= &info
->sourceMode
;
2507 info
->infoType
= DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE
;
2508 info
->adapterId
= *gpu_luid
;
2509 info
->id
= source_id
;
2511 mode
->width
= devmode
->dmPelsWidth
;
2512 mode
->height
= devmode
->dmPelsHeight
;
2513 mode
->pixelFormat
= get_dc_pixelformat( devmode
->dmBitsPerPel
);
2514 if (devmode
->dmFields
& DM_POSITION
)
2516 mode
->position
= devmode
->dmPosition
;
2520 mode
->position
.x
= 0;
2521 mode
->position
.y
= 0;
2525 static void set_path_source_info( DISPLAYCONFIG_PATH_SOURCE_INFO
*info
, const LUID
*gpu_luid
,
2526 UINT32 source_id
, UINT32 mode_index
)
2528 info
->adapterId
= *gpu_luid
;
2529 info
->id
= source_id
;
2530 info
->modeInfoIdx
= mode_index
;
2531 info
->statusFlags
= DISPLAYCONFIG_SOURCE_IN_USE
;
2534 static BOOL
source_mode_exists( const DISPLAYCONFIG_MODE_INFO
*modes
, UINT32 modes_count
,
2535 UINT32 source_id
, UINT32
*found_mode_index
)
2539 for (i
= 0; i
< modes_count
; i
++)
2541 if (modes
[i
].infoType
== DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE
&&
2542 modes
[i
].id
== source_id
)
2544 *found_mode_index
= i
;
2551 /***********************************************************************
2552 * NtUserQueryDisplayConfig (win32u.@)
2554 LONG WINAPI
NtUserQueryDisplayConfig( UINT32 flags
, UINT32
*paths_count
, DISPLAYCONFIG_PATH_INFO
*paths
,
2555 UINT32
*modes_count
, DISPLAYCONFIG_MODE_INFO
*modes
,
2556 DISPLAYCONFIG_TOPOLOGY_ID
*topology_id
)
2558 ULONG adapter_index
;
2560 UINT32 output_id
, source_mode_index
, path_index
= 0, mode_index
= 0;
2561 const LUID
*gpu_luid
;
2563 struct monitor
*monitor
;
2565 FIXME( "flags %#x, paths_count %p, paths %p, modes_count %p, modes %p, topology_id %p semi-stub\n",
2566 flags
, paths_count
, paths
, modes_count
, modes
, topology_id
);
2568 if (!paths_count
|| !modes_count
)
2569 return ERROR_INVALID_PARAMETER
;
2571 if (!*paths_count
|| !*modes_count
)
2572 return ERROR_INVALID_PARAMETER
;
2574 if (flags
!= QDC_ALL_PATHS
&&
2575 flags
!= QDC_ONLY_ACTIVE_PATHS
&&
2576 flags
!= QDC_DATABASE_CURRENT
)
2577 return ERROR_INVALID_PARAMETER
;
2579 if (((flags
== QDC_DATABASE_CURRENT
) && !topology_id
) ||
2580 ((flags
!= QDC_DATABASE_CURRENT
) && topology_id
))
2581 return ERROR_INVALID_PARAMETER
;
2583 if (flags
!= QDC_ONLY_ACTIVE_PATHS
)
2584 FIXME( "only returning active paths\n" );
2588 FIXME( "setting toplogyid to DISPLAYCONFIG_TOPOLOGY_INTERNAL\n" );
2589 *topology_id
= DISPLAYCONFIG_TOPOLOGY_INTERNAL
;
2592 if (!lock_display_devices())
2593 return ERROR_GEN_FAILURE
;
2595 ret
= ERROR_GEN_FAILURE
;
2597 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
2599 if (!(monitor
->dev
.state_flags
& DISPLAY_DEVICE_ACTIVE
))
2602 if (!monitor
->adapter
)
2605 adapter_index
= monitor
->adapter
->id
;
2606 gpu_luid
= &monitor
->adapter
->gpu_luid
;
2607 output_id
= monitor
->output_id
;
2609 memset( &devmode
, 0, sizeof(devmode
) );
2610 devmode
.dmSize
= sizeof(devmode
);
2611 if (!adapter_get_current_settings( monitor
->adapter
, &devmode
))
2616 if (path_index
== *paths_count
|| mode_index
== *modes_count
)
2618 ret
= ERROR_INSUFFICIENT_BUFFER
;
2622 paths
[path_index
].flags
= DISPLAYCONFIG_PATH_ACTIVE
;
2623 set_mode_target_info( &modes
[mode_index
], gpu_luid
, output_id
, flags
, &devmode
);
2624 set_path_target_info( &paths
[path_index
].targetInfo
, gpu_luid
, output_id
, mode_index
, &devmode
);
2627 if (mode_index
== *modes_count
)
2629 ret
= ERROR_INSUFFICIENT_BUFFER
;
2633 /* Multiple targets can be driven by the same source, ensure a mode
2634 * hasn't already been added for this source.
2636 if (!source_mode_exists( modes
, mode_index
, adapter_index
, &source_mode_index
))
2638 set_mode_source_info( &modes
[mode_index
], gpu_luid
, adapter_index
, &devmode
);
2639 source_mode_index
= mode_index
;
2642 set_path_source_info( &paths
[path_index
].sourceInfo
, gpu_luid
, adapter_index
, source_mode_index
);
2646 *paths_count
= path_index
;
2647 *modes_count
= mode_index
;
2648 ret
= ERROR_SUCCESS
;
2651 unlock_display_devices();
2655 /* display_lock mutex must be held */
2656 static struct display_device
*find_monitor_device( struct display_device
*adapter
, UINT index
)
2658 struct monitor
*monitor
;
2660 LIST_FOR_EACH_ENTRY(monitor
, &monitors
, struct monitor
, entry
)
2661 if (&monitor
->adapter
->dev
== adapter
&& index
== monitor
->id
)
2662 return &monitor
->dev
;
2664 WARN( "Failed to find adapter %s monitor with id %u.\n", debugstr_w(adapter
->device_name
), index
);
2668 /* display_lock mutex must be held */
2669 static struct display_device
*find_adapter_device_by_id( UINT index
)
2671 struct adapter
*adapter
;
2673 LIST_FOR_EACH_ENTRY(adapter
, &adapters
, struct adapter
, entry
)
2674 if (index
== adapter
->id
) return &adapter
->dev
;
2676 WARN( "Failed to find adapter with id %u.\n", index
);
2680 /* display_lock mutex must be held */
2681 static struct display_device
*find_adapter_device_by_name( UNICODE_STRING
*name
)
2683 SIZE_T len
= name
->Length
/ sizeof(WCHAR
);
2684 struct adapter
*adapter
;
2686 LIST_FOR_EACH_ENTRY(adapter
, &adapters
, struct adapter
, entry
)
2687 if (!wcsnicmp( name
->Buffer
, adapter
->dev
.device_name
, len
) && !adapter
->dev
.device_name
[len
])
2688 return &adapter
->dev
;
2690 WARN( "Failed to find adapter with name %s.\n", debugstr_us(name
) );
2694 /* Find and acquire the adapter matching name, or primary adapter if name is NULL.
2695 * If not NULL, the returned adapter needs to be released with adapter_release.
2697 static struct adapter
*find_adapter( UNICODE_STRING
*name
)
2699 struct display_device
*device
;
2700 struct adapter
*adapter
;
2702 if (!lock_display_devices()) return NULL
;
2704 if (name
&& name
->Length
) device
= find_adapter_device_by_name( name
);
2705 else device
= find_adapter_device_by_id( 0 ); /* use primary adapter */
2707 if (!device
) adapter
= NULL
;
2708 else adapter
= adapter_acquire( CONTAINING_RECORD( device
, struct adapter
, dev
) );
2710 unlock_display_devices();
2714 /***********************************************************************
2715 * NtUserEnumDisplayDevices (win32u.@)
2717 NTSTATUS WINAPI
NtUserEnumDisplayDevices( UNICODE_STRING
*device
, DWORD index
,
2718 DISPLAY_DEVICEW
*info
, DWORD flags
)
2720 struct display_device
*found
= NULL
;
2722 TRACE( "%s %u %p %#x\n", debugstr_us( device
), (int)index
, info
, (int)flags
);
2724 if (!info
|| !info
->cb
) return STATUS_UNSUCCESSFUL
;
2726 if (!lock_display_devices()) return STATUS_UNSUCCESSFUL
;
2728 if (!device
|| !device
->Length
) found
= find_adapter_device_by_id( index
);
2729 else if ((found
= find_adapter_device_by_name( device
))) found
= find_monitor_device( found
, index
);
2733 if (info
->cb
>= offsetof(DISPLAY_DEVICEW
, DeviceName
) + sizeof(info
->DeviceName
))
2734 lstrcpyW( info
->DeviceName
, found
->device_name
);
2735 if (info
->cb
>= offsetof(DISPLAY_DEVICEW
, DeviceString
) + sizeof(info
->DeviceString
))
2736 lstrcpyW( info
->DeviceString
, found
->device_string
);
2737 if (info
->cb
>= offsetof(DISPLAY_DEVICEW
, StateFlags
) + sizeof(info
->StateFlags
))
2738 info
->StateFlags
= found
->state_flags
;
2739 if (info
->cb
>= offsetof(DISPLAY_DEVICEW
, DeviceID
) + sizeof(info
->DeviceID
))
2740 lstrcpyW( info
->DeviceID
, (flags
& EDD_GET_DEVICE_INTERFACE_NAME
)
2741 ? found
->interface_name
: found
->device_id
);
2742 if (info
->cb
>= offsetof(DISPLAY_DEVICEW
, DeviceKey
) + sizeof(info
->DeviceKey
))
2743 lstrcpyW( info
->DeviceKey
, found
->device_key
);
2745 unlock_display_devices();
2746 return found
? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
;
2749 #define _X_FIELD(prefix, bits) \
2750 if ((fields) & prefix##_##bits) \
2752 p += sprintf( p, "%s%s", first ? "" : ",", #bits ); \
2756 static const char *_CDS_flags( DWORD fields
)
2762 _X_FIELD(CDS
, UPDATEREGISTRY
)
2764 _X_FIELD(CDS
, FULLSCREEN
)
2765 _X_FIELD(CDS
, GLOBAL
)
2766 _X_FIELD(CDS
, SET_PRIMARY
)
2767 _X_FIELD(CDS
, VIDEOPARAMETERS
)
2768 _X_FIELD(CDS
, ENABLE_UNSAFE_MODES
)
2769 _X_FIELD(CDS
, DISABLE_UNSAFE_MODES
)
2770 _X_FIELD(CDS
, RESET
)
2771 _X_FIELD(CDS
, RESET_EX
)
2772 _X_FIELD(CDS
, NORESET
)
2775 return wine_dbg_sprintf( "%s", buf
);
2778 static const char *_DM_fields( DWORD fields
)
2784 _X_FIELD(DM
, BITSPERPEL
)
2785 _X_FIELD(DM
, PELSWIDTH
)
2786 _X_FIELD(DM
, PELSHEIGHT
)
2787 _X_FIELD(DM
, DISPLAYFLAGS
)
2788 _X_FIELD(DM
, DISPLAYFREQUENCY
)
2789 _X_FIELD(DM
, POSITION
)
2790 _X_FIELD(DM
, DISPLAYORIENTATION
)
2793 return wine_dbg_sprintf( "%s", buf
);
2798 static void trace_devmode( const DEVMODEW
*devmode
)
2800 TRACE( "dmFields=%s ", _DM_fields(devmode
->dmFields
) );
2801 if (devmode
->dmFields
& DM_BITSPERPEL
)
2802 TRACE( "dmBitsPerPel=%u ", (int)devmode
->dmBitsPerPel
);
2803 if (devmode
->dmFields
& DM_PELSWIDTH
)
2804 TRACE( "dmPelsWidth=%u ", (int)devmode
->dmPelsWidth
);
2805 if (devmode
->dmFields
& DM_PELSHEIGHT
)
2806 TRACE( "dmPelsHeight=%u ", (int)devmode
->dmPelsHeight
);
2807 if (devmode
->dmFields
& DM_DISPLAYFREQUENCY
)
2808 TRACE( "dmDisplayFrequency=%u ", (int)devmode
->dmDisplayFrequency
);
2809 if (devmode
->dmFields
& DM_POSITION
)
2810 TRACE( "dmPosition=(%d,%d) ", (int)devmode
->dmPosition
.x
, (int)devmode
->dmPosition
.y
);
2811 if (devmode
->dmFields
& DM_DISPLAYFLAGS
)
2812 TRACE( "dmDisplayFlags=%#x ", (int)devmode
->dmDisplayFlags
);
2813 if (devmode
->dmFields
& DM_DISPLAYORIENTATION
)
2814 TRACE( "dmDisplayOrientation=%u ", (int)devmode
->dmDisplayOrientation
);
2818 static BOOL
is_detached_mode( const DEVMODEW
*mode
)
2820 return mode
->dmFields
& DM_POSITION
&&
2821 mode
->dmFields
& DM_PELSWIDTH
&&
2822 mode
->dmFields
& DM_PELSHEIGHT
&&
2823 mode
->dmPelsWidth
== 0 &&
2824 mode
->dmPelsHeight
== 0;
2827 static const DEVMODEW
*find_display_mode( const DEVMODEW
*modes
, DEVMODEW
*devmode
)
2829 const DEVMODEW
*mode
;
2831 if (is_detached_mode( devmode
)) return devmode
;
2833 for (mode
= modes
; mode
&& mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
2835 if ((mode
->dmFields
& DM_DISPLAYFLAGS
) && (mode
->dmDisplayFlags
& WINE_DM_UNSUPPORTED
))
2837 if ((devmode
->dmFields
& DM_BITSPERPEL
) && devmode
->dmBitsPerPel
&& devmode
->dmBitsPerPel
!= mode
->dmBitsPerPel
)
2839 if ((devmode
->dmFields
& DM_PELSWIDTH
) && devmode
->dmPelsWidth
!= mode
->dmPelsWidth
)
2841 if ((devmode
->dmFields
& DM_PELSHEIGHT
) && devmode
->dmPelsHeight
!= mode
->dmPelsHeight
)
2843 if ((devmode
->dmFields
& DM_DISPLAYFREQUENCY
) && devmode
->dmDisplayFrequency
!= mode
->dmDisplayFrequency
2844 && devmode
->dmDisplayFrequency
> 1 && mode
->dmDisplayFrequency
)
2846 if ((devmode
->dmFields
& DM_DISPLAYORIENTATION
) && devmode
->dmDisplayOrientation
!= mode
->dmDisplayOrientation
)
2848 if ((devmode
->dmFields
& DM_DISPLAYFLAGS
) && (mode
->dmFields
& DM_DISPLAYFLAGS
) &&
2849 (devmode
->dmDisplayFlags
& DM_INTERLACED
) != (mode
->dmDisplayFlags
& DM_INTERLACED
))
2851 if ((devmode
->dmFields
& DM_DISPLAYFIXEDOUTPUT
) && (mode
->dmFields
& DM_DISPLAYFIXEDOUTPUT
) &&
2852 devmode
->dmDisplayFixedOutput
!= mode
->dmDisplayFixedOutput
)
2861 static BOOL
adapter_get_full_mode( const struct adapter
*adapter
, const DEVMODEW
*devmode
, DEVMODEW
*full_mode
)
2863 const DEVMODEW
*adapter_mode
;
2867 trace_devmode( devmode
);
2869 if (devmode
->dmSize
< offsetof(DEVMODEW
, dmICMMethod
)) return FALSE
;
2870 if (!is_detached_mode( devmode
) &&
2871 (!(devmode
->dmFields
& DM_BITSPERPEL
) || !devmode
->dmBitsPerPel
) &&
2872 (!(devmode
->dmFields
& DM_PELSWIDTH
) || !devmode
->dmPelsWidth
) &&
2873 (!(devmode
->dmFields
& DM_PELSHEIGHT
) || !devmode
->dmPelsHeight
) &&
2874 (!(devmode
->dmFields
& DM_DISPLAYFREQUENCY
) || !devmode
->dmDisplayFrequency
))
2878 if (devmode
) memcpy( full_mode
, devmode
, devmode
->dmSize
);
2881 if (!adapter_get_registry_settings( adapter
, full_mode
)) return FALSE
;
2882 TRACE( "Return to original display mode\n" );
2885 if ((full_mode
->dmFields
& (DM_PELSWIDTH
| DM_PELSHEIGHT
)) != (DM_PELSWIDTH
| DM_PELSHEIGHT
))
2887 WARN( "devmode doesn't specify the resolution: %#x\n", (int)full_mode
->dmFields
);
2891 if (!is_detached_mode( full_mode
) && (!full_mode
->dmPelsWidth
|| !full_mode
->dmPelsHeight
|| !(full_mode
->dmFields
& DM_POSITION
)))
2893 DEVMODEW current_mode
= {.dmSize
= sizeof(DEVMODEW
)};
2895 if (!adapter_get_current_settings( adapter
, ¤t_mode
)) return FALSE
;
2896 if (!full_mode
->dmPelsWidth
) full_mode
->dmPelsWidth
= current_mode
.dmPelsWidth
;
2897 if (!full_mode
->dmPelsHeight
) full_mode
->dmPelsHeight
= current_mode
.dmPelsHeight
;
2898 if (!(full_mode
->dmFields
& DM_POSITION
))
2900 full_mode
->dmPosition
= current_mode
.dmPosition
;
2901 full_mode
->dmFields
|= DM_POSITION
;
2905 if ((adapter_mode
= find_display_mode( adapter
->modes
, full_mode
)) && adapter_mode
!= full_mode
)
2907 POINTL position
= full_mode
->dmPosition
;
2908 *full_mode
= *adapter_mode
;
2909 full_mode
->dmFields
|= DM_POSITION
;
2910 full_mode
->dmPosition
= position
;
2913 return adapter_mode
!= NULL
;
2916 static DEVMODEW
*get_display_settings( const WCHAR
*devname
, const DEVMODEW
*devmode
)
2918 DEVMODEW
*mode
, *displays
;
2919 struct adapter
*adapter
;
2922 /* allocate an extra mode for easier iteration */
2923 if (!(displays
= calloc( list_count( &adapters
) + 1, sizeof(DEVMODEW
) ))) return NULL
;
2926 LIST_FOR_EACH_ENTRY( adapter
, &adapters
, struct adapter
, entry
)
2928 mode
->dmSize
= sizeof(DEVMODEW
);
2929 if (devmode
&& !wcsicmp( devname
, adapter
->dev
.device_name
))
2930 memcpy( &mode
->dmFields
, &devmode
->dmFields
, devmode
->dmSize
- offsetof(DEVMODEW
, dmFields
) );
2933 if (!devname
) ret
= adapter_get_registry_settings( adapter
, mode
);
2934 else ret
= adapter_get_current_settings( adapter
, mode
);
2942 lstrcpyW( mode
->dmDeviceName
, adapter
->dev
.device_name
);
2943 mode
= NEXT_DEVMODEW(mode
);
2949 static INT
offset_length( POINT offset
)
2951 return offset
.x
* offset
.x
+ offset
.y
* offset
.y
;
2954 static void set_rect_from_devmode( RECT
*rect
, const DEVMODEW
*mode
)
2956 SetRect( rect
, mode
->dmPosition
.x
, mode
->dmPosition
.y
, mode
->dmPosition
.x
+ mode
->dmPelsWidth
,
2957 mode
->dmPosition
.y
+ mode
->dmPelsHeight
);
2960 /* Check if a rect overlaps with placed display rects */
2961 static BOOL
overlap_placed_displays( const RECT
*rect
, const DEVMODEW
*displays
)
2963 const DEVMODEW
*mode
;
2966 for (mode
= displays
; mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
2968 set_rect_from_devmode( &intersect
, mode
);
2969 if ((mode
->dmFields
& DM_POSITION
) && intersect_rect( &intersect
, &intersect
, rect
)) return TRUE
;
2975 /* Get the offset with minimum length to place a display next to the placed displays with no spacing and overlaps */
2976 static POINT
get_placement_offset( const DEVMODEW
*displays
, const DEVMODEW
*placing
)
2978 POINT points
[8], left_top
, offset
, min_offset
= {0, 0};
2979 INT point_idx
, point_count
, vertex_idx
;
2980 BOOL has_placed
= FALSE
, first
= TRUE
;
2981 RECT desired_rect
, rect
;
2982 const DEVMODEW
*mode
;
2985 set_rect_from_devmode( &desired_rect
, placing
);
2987 /* If the display to be placed is detached, no offset is needed to place it */
2988 if (IsRectEmpty( &desired_rect
)) return min_offset
;
2990 /* If there is no placed and attached display, place this display as it is */
2991 for (mode
= displays
; mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
2993 set_rect_from_devmode( &rect
, mode
);
2994 if ((mode
->dmFields
& DM_POSITION
) && !IsRectEmpty( &rect
))
3001 if (!has_placed
) return min_offset
;
3003 /* Try to place this display with each of its four vertices at every vertex of the placed
3004 * displays and see which combination has the minimum offset length */
3005 width
= desired_rect
.right
- desired_rect
.left
;
3006 height
= desired_rect
.bottom
- desired_rect
.top
;
3008 for (mode
= displays
; mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
3010 set_rect_from_devmode( &rect
, mode
);
3011 if (!(mode
->dmFields
& DM_POSITION
) || IsRectEmpty( &rect
)) continue;
3013 /* Get four vertices of the placed display rectangle */
3014 points
[0].x
= rect
.left
;
3015 points
[0].y
= rect
.top
;
3016 points
[1].x
= rect
.left
;
3017 points
[1].y
= rect
.bottom
;
3018 points
[2].x
= rect
.right
;
3019 points
[2].y
= rect
.top
;
3020 points
[3].x
= rect
.right
;
3021 points
[3].y
= rect
.bottom
;
3024 /* Intersected points when moving the display to be placed horizontally */
3025 if (desired_rect
.bottom
>= rect
.top
&& desired_rect
.top
<= rect
.bottom
)
3027 points
[point_count
].x
= rect
.left
;
3028 points
[point_count
++].y
= desired_rect
.top
;
3029 points
[point_count
].x
= rect
.right
;
3030 points
[point_count
++].y
= desired_rect
.top
;
3032 /* Intersected points when moving the display to be placed vertically */
3033 if (desired_rect
.left
<= rect
.right
&& desired_rect
.right
>= rect
.left
)
3035 points
[point_count
].x
= desired_rect
.left
;
3036 points
[point_count
++].y
= rect
.top
;
3037 points
[point_count
].x
= desired_rect
.left
;
3038 points
[point_count
++].y
= rect
.bottom
;
3041 /* Try moving each vertex of the display rectangle to each points */
3042 for (point_idx
= 0; point_idx
< point_count
; ++point_idx
)
3044 for (vertex_idx
= 0; vertex_idx
< 4; ++vertex_idx
)
3048 /* Move the bottom right vertex to the point */
3050 left_top
.x
= points
[point_idx
].x
- width
;
3051 left_top
.y
= points
[point_idx
].y
- height
;
3053 /* Move the bottom left vertex to the point */
3055 left_top
.x
= points
[point_idx
].x
;
3056 left_top
.y
= points
[point_idx
].y
- height
;
3058 /* Move the top right vertex to the point */
3060 left_top
.x
= points
[point_idx
].x
- width
;
3061 left_top
.y
= points
[point_idx
].y
;
3063 /* Move the top left vertex to the point */
3065 left_top
.x
= points
[point_idx
].x
;
3066 left_top
.y
= points
[point_idx
].y
;
3070 offset
.x
= left_top
.x
- desired_rect
.left
;
3071 offset
.y
= left_top
.y
- desired_rect
.top
;
3072 rect
= desired_rect
;
3073 OffsetRect( &rect
, offset
.x
, offset
.y
);
3074 if (!overlap_placed_displays( &rect
, displays
))
3078 min_offset
= offset
;
3083 if (offset_length( offset
) < offset_length( min_offset
)) min_offset
= offset
;
3092 static void place_all_displays( DEVMODEW
*displays
)
3094 POINT min_offset
, offset
;
3095 DEVMODEW
*mode
, *placing
;
3097 for (mode
= displays
; mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
3098 mode
->dmFields
&= ~DM_POSITION
;
3100 /* Place all displays with no extra space between them and no overlapping */
3103 /* Place the unplaced display with the minimum offset length first */
3105 for (mode
= displays
; mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
3107 if (mode
->dmFields
& DM_POSITION
) continue;
3109 offset
= get_placement_offset( displays
, mode
);
3110 if (!placing
|| offset_length( offset
) < offset_length( min_offset
))
3112 min_offset
= offset
;
3117 /* If all displays are placed */
3118 if (!placing
) break;
3120 placing
->dmPosition
.x
+= min_offset
.x
;
3121 placing
->dmPosition
.y
+= min_offset
.y
;
3122 placing
->dmFields
|= DM_POSITION
;
3126 static BOOL
all_detached_settings( const DEVMODEW
*displays
)
3128 const DEVMODEW
*mode
;
3130 for (mode
= displays
; mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
3131 if (!is_detached_mode( mode
)) return FALSE
;
3136 static LONG
apply_display_settings( const WCHAR
*devname
, const DEVMODEW
*devmode
,
3137 HWND hwnd
, DWORD flags
, void *lparam
)
3139 WCHAR primary_name
[CCHDEVICENAME
];
3140 struct display_device
*primary
;
3141 DEVMODEW
*mode
, *displays
;
3142 struct adapter
*adapter
;
3145 if (!lock_display_devices()) return DISP_CHANGE_FAILED
;
3146 if (!(displays
= get_display_settings( devname
, devmode
)))
3148 unlock_display_devices();
3149 return DISP_CHANGE_FAILED
;
3152 if (all_detached_settings( displays
))
3154 unlock_display_devices();
3155 WARN( "Detaching all modes is not permitted.\n" );
3157 return DISP_CHANGE_SUCCESSFUL
;
3160 place_all_displays( displays
);
3162 if (!(primary
= find_adapter_device_by_id( 0 ))) primary_name
[0] = 0;
3163 else wcscpy( primary_name
, primary
->device_name
);
3165 /* use the default implementation in virtual desktop mode */
3166 if (is_virtual_desktop()) ret
= E_NOTIMPL
;
3167 else ret
= user_driver
->pChangeDisplaySettings( displays
, primary_name
, hwnd
, flags
, lparam
);
3169 if (ret
== E_NOTIMPL
)
3171 /* default implementation: write current display settings to the registry. */
3173 LIST_FOR_EACH_ENTRY( adapter
, &adapters
, struct adapter
, entry
)
3175 if (!adapter_set_current_settings( adapter
, mode
))
3176 WARN( "Failed to write adapter %s current mode.\n", debugstr_w(adapter
->dev
.device_name
) );
3177 mode
= NEXT_DEVMODEW(mode
);
3179 ret
= DISP_CHANGE_SUCCESSFUL
;
3181 unlock_display_devices();
3184 if (ret
) return ret
;
3186 if (!update_display_cache( TRUE
))
3187 WARN( "Failed to update display cache after mode change.\n" );
3189 if ((adapter
= find_adapter( NULL
)))
3191 DEVMODEW current_mode
= {.dmSize
= sizeof(DEVMODEW
)};
3193 if (!adapter_get_current_settings( adapter
, ¤t_mode
)) WARN( "Failed to get primary adapter current display settings.\n" );
3194 adapter_release( adapter
);
3196 NtUserClipCursor( NULL
);
3197 send_notify_message( NtUserGetDesktopWindow(), WM_DISPLAYCHANGE
, current_mode
.dmBitsPerPel
,
3198 MAKELPARAM( current_mode
.dmPelsWidth
, current_mode
.dmPelsHeight
), FALSE
);
3199 send_message_timeout( HWND_BROADCAST
, WM_DISPLAYCHANGE
, current_mode
.dmBitsPerPel
,
3200 MAKELPARAM( current_mode
.dmPelsWidth
, current_mode
.dmPelsHeight
),
3201 SMTO_ABORTIFHUNG
, 2000, FALSE
);
3202 /* post clip_fullscreen_window request to the foreground window */
3203 NtUserPostMessage( NtUserGetForegroundWindow(), WM_WINE_CLIPCURSOR
, SET_CURSOR_FSCLIP
, 0 );
3209 /***********************************************************************
3210 * NtUserChangeDisplaySettings (win32u.@)
3212 LONG WINAPI
NtUserChangeDisplaySettings( UNICODE_STRING
*devname
, DEVMODEW
*devmode
, HWND hwnd
,
3213 DWORD flags
, void *lparam
)
3215 DEVMODEW full_mode
= {.dmSize
= sizeof(DEVMODEW
)};
3216 int ret
= DISP_CHANGE_SUCCESSFUL
;
3217 struct adapter
*adapter
;
3219 TRACE( "%s %p %p %#x %p\n", debugstr_us(devname
), devmode
, hwnd
, (int)flags
, lparam
);
3220 TRACE( "flags=%s\n", _CDS_flags(flags
) );
3222 if ((!devname
|| !devname
->Length
) && !devmode
) return apply_display_settings( NULL
, NULL
, hwnd
, flags
, lparam
);
3224 if (!(adapter
= find_adapter( devname
))) return DISP_CHANGE_BADPARAM
;
3226 if (!adapter_get_full_mode( adapter
, devmode
, &full_mode
)) ret
= DISP_CHANGE_BADMODE
;
3227 else if ((flags
& CDS_UPDATEREGISTRY
) && !adapter_set_registry_settings( adapter
, &full_mode
)) ret
= DISP_CHANGE_NOTUPDATED
;
3228 else if (flags
& (CDS_TEST
| CDS_NORESET
)) ret
= DISP_CHANGE_SUCCESSFUL
;
3229 else ret
= apply_display_settings( adapter
->dev
.device_name
, &full_mode
, hwnd
, flags
, lparam
);
3230 adapter_release( adapter
);
3232 if (ret
) ERR( "Changing %s display settings returned %d.\n", debugstr_us(devname
), ret
);
3236 static BOOL
adapter_enum_display_settings( const struct adapter
*adapter
, UINT index
, DEVMODEW
*devmode
, UINT flags
)
3238 DEVMODEW current_mode
= {.dmSize
= sizeof(DEVMODEW
)};
3239 const DEVMODEW
*adapter_mode
;
3241 if (!(flags
& EDS_ROTATEDMODE
) && !adapter_get_current_settings( adapter
, ¤t_mode
))
3243 WARN( "Failed to query current display mode for EDS_ROTATEDMODE flag.\n" );
3247 for (adapter_mode
= adapter
->modes
; adapter_mode
->dmSize
; adapter_mode
= NEXT_DEVMODEW(adapter_mode
))
3249 if (!(flags
& EDS_ROTATEDMODE
) && (adapter_mode
->dmFields
& DM_DISPLAYORIENTATION
) &&
3250 adapter_mode
->dmDisplayOrientation
!= current_mode
.dmDisplayOrientation
)
3252 if (!(flags
& EDS_RAWMODE
) && (adapter_mode
->dmFields
& DM_DISPLAYFLAGS
) &&
3253 (adapter_mode
->dmDisplayFlags
& WINE_DM_UNSUPPORTED
))
3257 memcpy( &devmode
->dmFields
, &adapter_mode
->dmFields
, devmode
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmFields
) );
3258 devmode
->dmDisplayFlags
&= ~WINE_DM_UNSUPPORTED
;
3263 WARN( "device %s, index %#x, flags %#x display mode not found.\n",
3264 debugstr_w( adapter
->dev
.device_name
), index
, flags
);
3265 RtlSetLastWin32Error( ERROR_NO_MORE_FILES
);
3269 /***********************************************************************
3270 * NtUserEnumDisplaySettings (win32u.@)
3272 BOOL WINAPI
NtUserEnumDisplaySettings( UNICODE_STRING
*device
, DWORD index
, DEVMODEW
*devmode
, DWORD flags
)
3274 static const WCHAR wine_display_driverW
[] = {'W','i','n','e',' ','D','i','s','p','l','a','y',' ','D','r','i','v','e','r',0};
3275 struct adapter
*adapter
;
3278 TRACE( "device %s, index %#x, devmode %p, flags %#x\n",
3279 debugstr_us(device
), (int)index
, devmode
, (int)flags
);
3281 if (!(adapter
= find_adapter( device
))) return FALSE
;
3283 lstrcpynW( devmode
->dmDeviceName
, wine_display_driverW
, ARRAY_SIZE(devmode
->dmDeviceName
) );
3284 devmode
->dmSpecVersion
= DM_SPECVERSION
;
3285 devmode
->dmDriverVersion
= DM_SPECVERSION
;
3286 devmode
->dmSize
= offsetof(DEVMODEW
, dmICMMethod
);
3287 devmode
->dmDriverExtra
= 0;
3289 if (index
== ENUM_REGISTRY_SETTINGS
) ret
= adapter_get_registry_settings( adapter
, devmode
);
3290 else if (index
== ENUM_CURRENT_SETTINGS
) ret
= adapter_get_current_settings( adapter
, devmode
);
3291 else ret
= adapter_enum_display_settings( adapter
, index
, devmode
, flags
);
3292 adapter_release( adapter
);
3294 if (!ret
) WARN( "Failed to query %s display settings.\n", debugstr_us(device
) );
3295 else TRACE( "position %dx%d, resolution %ux%u, frequency %u, depth %u, orientation %#x.\n",
3296 (int)devmode
->dmPosition
.x
, (int)devmode
->dmPosition
.y
, (int)devmode
->dmPelsWidth
,
3297 (int)devmode
->dmPelsHeight
, (int)devmode
->dmDisplayFrequency
,
3298 (int)devmode
->dmBitsPerPel
, (int)devmode
->dmDisplayOrientation
);
3302 struct monitor_enum_info
3308 static unsigned int active_monitor_count(void)
3310 struct monitor
*monitor
;
3311 unsigned int count
= 0;
3313 LIST_FOR_EACH_ENTRY(monitor
, &monitors
, struct monitor
, entry
)
3315 if ((monitor
->dev
.state_flags
& DISPLAY_DEVICE_ACTIVE
)) count
++;
3320 INT
get_display_depth( UNICODE_STRING
*name
)
3322 struct display_device
*device
;
3326 if (!lock_display_devices())
3329 if (name
&& name
->Length
)
3330 device
= find_adapter_device_by_name( name
);
3332 device
= find_adapter_device_by_id( 0 ); /* use primary adapter */
3336 unlock_display_devices();
3340 is_primary
= !!(device
->state_flags
& DISPLAY_DEVICE_PRIMARY_DEVICE
);
3342 /* use the default implementation in virtual desktop mode */
3343 if (is_virtual_desktop()) depth
= -1;
3344 else depth
= user_driver
->pGetDisplayDepth( device
->device_name
, is_primary
);
3348 struct adapter
*adapter
= CONTAINING_RECORD( device
, struct adapter
, dev
);
3349 DEVMODEW current_mode
= {.dmSize
= sizeof(DEVMODEW
)};
3351 if (!adapter_get_current_settings( adapter
, ¤t_mode
)) depth
= 32;
3352 else depth
= current_mode
.dmBitsPerPel
;
3355 unlock_display_devices();
3359 /***********************************************************************
3360 * NtUserEnumDisplayMonitors (win32u.@)
3362 BOOL WINAPI
NtUserEnumDisplayMonitors( HDC hdc
, RECT
*rect
, MONITORENUMPROC proc
, LPARAM lparam
)
3364 struct monitor_enum_info enum_buf
[8], *enum_info
= enum_buf
;
3365 struct enum_display_monitor_params params
;
3366 struct monitor
*monitor
;
3367 unsigned int count
= 0, i
;
3375 if (!(dc
= get_dc_ptr( hdc
))) return FALSE
;
3376 origin
.x
= dc
->attr
->vis_rect
.left
;
3377 origin
.y
= dc
->attr
->vis_rect
.top
;
3378 release_dc_ptr( dc
);
3379 if (NtGdiGetAppClipBox( hdc
, &limit
) == ERROR
) return FALSE
;
3383 origin
.x
= origin
.y
= 0;
3384 limit
.left
= limit
.top
= INT_MIN
;
3385 limit
.right
= limit
.bottom
= INT_MAX
;
3387 if (rect
&& !intersect_rect( &limit
, &limit
, rect
)) return TRUE
;
3389 if (!lock_display_devices()) return FALSE
;
3391 count
= list_count( &monitors
);
3392 if (!count
|| (count
> ARRAYSIZE(enum_buf
) &&
3393 !(enum_info
= malloc( count
* sizeof(*enum_info
) ))))
3395 unlock_display_devices();
3400 LIST_FOR_EACH_ENTRY(monitor
, &monitors
, struct monitor
, entry
)
3404 if (!(monitor
->dev
.state_flags
& DISPLAY_DEVICE_ACTIVE
)) continue;
3406 monrect
= map_dpi_rect( monitor
->rc_monitor
, get_monitor_dpi( monitor
->handle
),
3408 OffsetRect( &monrect
, -origin
.x
, -origin
.y
);
3409 if (!intersect_rect( &monrect
, &monrect
, &limit
)) continue;
3410 if (monitor
->is_clone
) continue;
3412 enum_info
[count
].handle
= monitor
->handle
;
3413 enum_info
[count
].rect
= monrect
;
3417 unlock_display_devices();
3421 params
.lparam
= lparam
;
3422 for (i
= 0; i
< count
; i
++)
3426 params
.monitor
= enum_info
[i
].handle
;
3427 params
.rect
= enum_info
[i
].rect
;
3428 if (!KeUserModeCallback( NtUserCallEnumDisplayMonitor
, ¶ms
, sizeof(params
),
3429 &ret_ptr
, &ret_len
))
3435 if (enum_info
!= enum_buf
) free( enum_info
);
3439 BOOL
get_monitor_info( HMONITOR handle
, MONITORINFO
*info
)
3441 struct monitor
*monitor
;
3442 UINT dpi_from
, dpi_to
;
3444 if (info
->cbSize
!= sizeof(MONITORINFOEXW
) && info
->cbSize
!= sizeof(MONITORINFO
)) return FALSE
;
3446 if (!lock_display_devices()) return FALSE
;
3448 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
3450 if (monitor
->handle
!= handle
) continue;
3451 if (!(monitor
->dev
.state_flags
& DISPLAY_DEVICE_ACTIVE
)) break;
3453 /* FIXME: map dpi */
3454 info
->rcMonitor
= monitor
->rc_monitor
;
3455 info
->rcWork
= monitor
->rc_work
;
3456 info
->dwFlags
= monitor
->flags
;
3457 if (info
->cbSize
>= sizeof(MONITORINFOEXW
))
3459 if (monitor
->adapter
)
3460 lstrcpyW( ((MONITORINFOEXW
*)info
)->szDevice
, monitor
->adapter
->dev
.device_name
);
3462 asciiz_to_unicode( ((MONITORINFOEXW
*)info
)->szDevice
, "WinDisc" );
3464 unlock_display_devices();
3466 if ((dpi_to
= get_thread_dpi()))
3468 dpi_from
= get_monitor_dpi( handle
);
3469 info
->rcMonitor
= map_dpi_rect( info
->rcMonitor
, dpi_from
, dpi_to
);
3470 info
->rcWork
= map_dpi_rect( info
->rcWork
, dpi_from
, dpi_to
);
3472 TRACE( "flags %04x, monitor %s, work %s\n", (int)info
->dwFlags
,
3473 wine_dbgstr_rect(&info
->rcMonitor
), wine_dbgstr_rect(&info
->rcWork
));
3477 unlock_display_devices();
3478 WARN( "invalid handle %p\n", handle
);
3479 RtlSetLastWin32Error( ERROR_INVALID_MONITOR_HANDLE
);
3483 HMONITOR
monitor_from_rect( const RECT
*rect
, UINT flags
, UINT dpi
)
3485 HMONITOR primary
= 0, nearest
= 0, ret
= 0;
3486 UINT max_area
= 0, min_distance
= ~0u;
3487 struct monitor
*monitor
;
3490 r
= map_dpi_rect( *rect
, dpi
, system_dpi
);
3491 if (IsRectEmpty( &r
))
3493 r
.right
= r
.left
+ 1;
3494 r
.bottom
= r
.top
+ 1;
3497 if (!lock_display_devices()) return 0;
3499 LIST_FOR_EACH_ENTRY(monitor
, &monitors
, struct monitor
, entry
)
3502 RECT monitor_rect
= map_dpi_rect( monitor
->rc_monitor
, get_monitor_dpi( monitor
->handle
),
3505 if (intersect_rect( &intersect
, &monitor_rect
, &r
))
3507 /* check for larger intersecting area */
3508 UINT area
= (intersect
.right
- intersect
.left
) * (intersect
.bottom
- intersect
.top
);
3509 if (area
> max_area
)
3512 ret
= monitor
->handle
;
3515 else if (!max_area
) /* if not intersecting, check for min distance */
3520 if (r
.right
<= monitor_rect
.left
) x
= monitor_rect
.left
- r
.right
;
3521 else if (monitor_rect
.right
<= r
.left
) x
= r
.left
- monitor_rect
.right
;
3523 if (r
.bottom
<= monitor_rect
.top
) y
= monitor_rect
.top
- r
.bottom
;
3524 else if (monitor_rect
.bottom
<= r
.top
) y
= r
.top
- monitor_rect
.bottom
;
3526 distance
= x
* x
+ y
* y
;
3527 if (distance
< min_distance
)
3529 min_distance
= distance
;
3530 nearest
= monitor
->handle
;
3534 if (monitor
->flags
& MONITORINFOF_PRIMARY
) primary
= monitor
->handle
;
3537 unlock_display_devices();
3541 if (flags
& MONITOR_DEFAULTTOPRIMARY
) ret
= primary
;
3542 else if (flags
& MONITOR_DEFAULTTONEAREST
) ret
= nearest
;
3545 TRACE( "%s flags %x returning %p\n", wine_dbgstr_rect(rect
), flags
, ret
);
3549 HMONITOR
monitor_from_point( POINT pt
, UINT flags
, UINT dpi
)
3552 SetRect( &rect
, pt
.x
, pt
.y
, pt
.x
+ 1, pt
.y
+ 1 );
3553 return monitor_from_rect( &rect
, flags
, dpi
);
3556 /* see MonitorFromWindow */
3557 HMONITOR
monitor_from_window( HWND hwnd
, UINT flags
, UINT dpi
)
3562 TRACE( "(%p, 0x%08x)\n", hwnd
, flags
);
3564 wp
.length
= sizeof(wp
);
3565 if (is_iconic( hwnd
) && NtUserGetWindowPlacement( hwnd
, &wp
))
3566 return monitor_from_rect( &wp
.rcNormalPosition
, flags
, dpi
);
3568 if (get_window_rect( hwnd
, &rect
, dpi
))
3569 return monitor_from_rect( &rect
, flags
, dpi
);
3571 if (!(flags
& (MONITOR_DEFAULTTOPRIMARY
|MONITOR_DEFAULTTONEAREST
))) return 0;
3572 /* retrieve the primary */
3573 SetRect( &rect
, 0, 0, 1, 1 );
3574 return monitor_from_rect( &rect
, flags
, dpi
);
3577 /***********************************************************************
3578 * NtUserGetSystemDpiForProcess (win32u.@)
3580 ULONG WINAPI
NtUserGetSystemDpiForProcess( HANDLE process
)
3582 if (process
&& process
!= GetCurrentProcess())
3584 FIXME( "not supported on other process %p\n", process
);
3591 /***********************************************************************
3592 * NtUserGetDpiForMonitor (win32u.@)
3594 BOOL WINAPI
NtUserGetDpiForMonitor( HMONITOR monitor
, UINT type
, UINT
*x
, UINT
*y
)
3598 RtlSetLastWin32Error( ERROR_BAD_ARGUMENTS
);
3603 RtlSetLastWin32Error( ERROR_INVALID_ADDRESS
);
3606 switch (get_thread_dpi_awareness())
3608 case DPI_AWARENESS_UNAWARE
: *x
= *y
= USER_DEFAULT_SCREEN_DPI
; break;
3609 case DPI_AWARENESS_SYSTEM_AWARE
: *x
= *y
= system_dpi
; break;
3610 default: *x
= *y
= get_monitor_dpi( monitor
); break;
3615 /**********************************************************************
3616 * LogicalToPhysicalPointForPerMonitorDPI (win32u.@)
3618 BOOL WINAPI
NtUserLogicalToPerMonitorDPIPhysicalPoint( HWND hwnd
, POINT
*pt
)
3622 if (!get_window_rect( hwnd
, &rect
, get_thread_dpi() )) return FALSE
;
3623 if (pt
->x
< rect
.left
|| pt
->y
< rect
.top
|| pt
->x
> rect
.right
|| pt
->y
> rect
.bottom
) return FALSE
;
3624 *pt
= point_win_to_phys_dpi( hwnd
, *pt
);
3628 /**********************************************************************
3629 * NtUserPerMonitorDPIPhysicalToLogicalPoint (win32u.@)
3631 BOOL WINAPI
NtUserPerMonitorDPIPhysicalToLogicalPoint( HWND hwnd
, POINT
*pt
)
3636 if (get_window_rect( hwnd
, &rect
, 0 ) &&
3637 pt
->x
>= rect
.left
&& pt
->y
>= rect
.top
&& pt
->x
<= rect
.right
&& pt
->y
<= rect
.bottom
)
3639 *pt
= point_phys_to_win_dpi( hwnd
, *pt
);
3645 /* retrieve the cached base keys for a given entry */
3646 static BOOL
get_base_keys( enum parameter_key index
, HKEY
*base_key
, HKEY
*volatile_key
)
3648 static HKEY base_keys
[NB_PARAM_KEYS
];
3649 static HKEY volatile_keys
[NB_PARAM_KEYS
];
3653 if (!base_keys
[index
] && base_key
)
3655 if (!(key
= reg_create_key( hkcu_key
, bufferW
,
3656 asciiz_to_unicode( bufferW
, parameter_key_names
[index
] ) - sizeof(WCHAR
),
3659 if (InterlockedCompareExchangePointer( (void **)&base_keys
[index
], key
, 0 ))
3662 if (!volatile_keys
[index
] && volatile_key
)
3664 if (!(key
= reg_create_key( volatile_base_key
, bufferW
,
3665 asciiz_to_unicode( bufferW
, parameter_key_names
[index
] ) - sizeof(WCHAR
),
3666 REG_OPTION_VOLATILE
, NULL
)))
3668 if (InterlockedCompareExchangePointer( (void **)&volatile_keys
[index
], key
, 0 ))
3671 if (base_key
) *base_key
= base_keys
[index
];
3672 if (volatile_key
) *volatile_key
= volatile_keys
[index
];
3676 /* load a value to a registry entry */
3677 static DWORD
load_entry( struct sysparam_entry
*entry
, void *data
, DWORD size
)
3680 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
3682 HKEY base_key
, volatile_key
;
3684 if (!get_base_keys( entry
->base_key
, &base_key
, &volatile_key
)) return FALSE
;
3686 if (!(count
= query_reg_ascii_value( volatile_key
, entry
->regval
, value
, sizeof(buffer
) )))
3687 count
= query_reg_ascii_value( base_key
, entry
->regval
, value
, sizeof(buffer
) );
3691 /* make sure strings are null-terminated */
3692 if (value
->Type
== REG_SZ
) ((WCHAR
*)value
->Data
)[count
/ sizeof(WCHAR
) - 1] = 0;
3694 if (count
) memcpy( data
, value
->Data
, count
);
3695 entry
->loaded
= TRUE
;
3699 /* save a value to a registry entry */
3700 static BOOL
save_entry( const struct sysparam_entry
*entry
, const void *data
, DWORD size
,
3701 DWORD type
, UINT flags
)
3703 HKEY base_key
, volatile_key
;
3706 asciiz_to_unicode( nameW
, entry
->regval
);
3707 if (flags
& SPIF_UPDATEINIFILE
)
3709 if (!get_base_keys( entry
->base_key
, &base_key
, &volatile_key
)) return FALSE
;
3710 if (!set_reg_value( base_key
, nameW
, type
, data
, size
)) return FALSE
;
3711 reg_delete_value( volatile_key
, nameW
);
3713 if (entry
->mirror
&& get_base_keys( entry
->mirror_key
, &base_key
, NULL
))
3715 asciiz_to_unicode( nameW
, entry
->mirror
);
3716 set_reg_value( base_key
, nameW
, type
, data
, size
);
3721 if (!get_base_keys( entry
->base_key
, NULL
, &volatile_key
)) return FALSE
;
3722 if (!set_reg_value( volatile_key
, nameW
, type
, data
, size
)) return FALSE
;
3727 /* save a string value to a registry entry */
3728 static BOOL
save_entry_string( const struct sysparam_entry
*entry
, const WCHAR
*str
, UINT flags
)
3730 return save_entry( entry
, str
, (lstrlenW(str
) + 1) * sizeof(WCHAR
), REG_SZ
, flags
);
3733 /* initialize an entry in the registry if missing */
3734 static BOOL
init_entry( struct sysparam_entry
*entry
, const void *data
, DWORD size
, DWORD type
)
3736 KEY_VALUE_PARTIAL_INFORMATION value
;
3737 UNICODE_STRING name
;
3743 if (!get_base_keys( entry
->base_key
, &base_key
, NULL
)) return FALSE
;
3745 name
.Buffer
= nameW
;
3746 name
.MaximumLength
= asciiz_to_unicode( nameW
, entry
->regval
);
3747 name
.Length
= name
.MaximumLength
- sizeof(WCHAR
);
3748 status
= NtQueryValueKey( base_key
, &name
, KeyValuePartialInformation
,
3749 &value
, sizeof(value
), &count
);
3750 if (!status
|| status
== STATUS_BUFFER_OVERFLOW
) return TRUE
;
3752 if (!set_reg_value( base_key
, nameW
, type
, data
, size
)) return FALSE
;
3753 if (entry
->mirror
&& get_base_keys( entry
->mirror_key
, &base_key
, NULL
))
3755 asciiz_to_unicode( nameW
, entry
->mirror
);
3756 set_reg_value( base_key
, nameW
, type
, data
, size
);
3758 entry
->loaded
= TRUE
;
3762 /* initialize a string value in the registry if missing */
3763 static BOOL
init_entry_string( struct sysparam_entry
*entry
, const WCHAR
*str
)
3765 return init_entry( entry
, str
, (lstrlenW(str
) + 1) * sizeof(WCHAR
), REG_SZ
);
3768 /* set an int parameter in the registry */
3769 static BOOL
set_int_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3774 sprintf( buf
, "%d", int_param
);
3775 asciiz_to_unicode( bufW
, buf
);
3776 if (!save_entry_string( &entry
->hdr
, bufW
, flags
)) return FALSE
;
3777 entry
->uint
.val
= int_param
;
3778 entry
->hdr
.loaded
= TRUE
;
3782 /* initialize an int parameter */
3783 static BOOL
init_int_entry( union sysparam_all_entry
*entry
)
3788 sprintf( buf
, "%d", entry
->uint
.val
);
3789 asciiz_to_unicode( bufW
, buf
);
3790 return init_entry_string( &entry
->hdr
, bufW
);
3793 /* load a uint parameter from the registry */
3794 static BOOL
get_uint_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3796 if (!ptr_param
) return FALSE
;
3798 if (!entry
->hdr
.loaded
)
3801 if (load_entry( &entry
->hdr
, buf
, sizeof(buf
) )) entry
->uint
.val
= wcstol( buf
, NULL
, 10 );
3803 *(UINT
*)ptr_param
= entry
->uint
.val
;
3807 /* set a uint parameter in the registry */
3808 static BOOL
set_uint_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3813 sprintf( buf
, "%u", int_param
);
3814 asciiz_to_unicode( bufW
, buf
);
3815 if (!save_entry_string( &entry
->hdr
, bufW
, flags
)) return FALSE
;
3816 entry
->uint
.val
= int_param
;
3817 entry
->hdr
.loaded
= TRUE
;
3821 /* initialize a uint parameter */
3822 static BOOL
init_uint_entry( union sysparam_all_entry
*entry
)
3827 sprintf( buf
, "%u", entry
->uint
.val
);
3828 asciiz_to_unicode( bufW
, buf
);
3829 return init_entry_string( &entry
->hdr
, bufW
);
3832 /* load a twips parameter from the registry */
3833 static BOOL
get_twips_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3837 if (!ptr_param
) return FALSE
;
3839 if (!entry
->hdr
.loaded
)
3842 if (load_entry( &entry
->hdr
, buf
, sizeof(buf
) )) entry
->uint
.val
= wcstol( buf
, NULL
, 10 );
3845 /* Dimensions are quoted as being "twips" values if negative and pixels if positive.
3846 * One inch is 1440 twips.
3848 * Technical Reference to the Windows 2000 Registry ->
3849 * HKEY_CURRENT_USER -> Control Panel -> Desktop -> WindowMetrics
3851 val
= entry
->uint
.val
;
3853 val
= muldiv( -val
, dpi
, 1440 );
3855 val
= map_to_dpi( val
, dpi
);
3857 *(int *)ptr_param
= val
;
3861 /* set a twips parameter in the registry */
3862 static BOOL
set_twips_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3864 int val
= int_param
;
3865 if (val
> 0) val
= map_from_system_dpi( val
);
3866 return set_int_entry( entry
, val
, ptr_param
, flags
);
3869 /* load a bool parameter from the registry */
3870 static BOOL
get_bool_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3872 if (!ptr_param
) return FALSE
;
3874 if (!entry
->hdr
.loaded
)
3877 if (load_entry( &entry
->hdr
, buf
, sizeof(buf
) )) entry
->bool.val
= wcstol( buf
, NULL
, 10 ) != 0;
3879 *(UINT
*)ptr_param
= entry
->bool.val
;
3883 /* set a bool parameter in the registry */
3884 static BOOL
set_bool_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3886 WCHAR buf
[] = { int_param
? '1' : '0', 0 };
3888 if (!save_entry_string( &entry
->hdr
, buf
, flags
)) return FALSE
;
3889 entry
->bool.val
= int_param
!= 0;
3890 entry
->hdr
.loaded
= TRUE
;
3894 /* initialize a bool parameter */
3895 static BOOL
init_bool_entry( union sysparam_all_entry
*entry
)
3897 WCHAR buf
[] = { entry
->bool.val
? '1' : '0', 0 };
3899 return init_entry_string( &entry
->hdr
, buf
);
3902 /* load a bool parameter using Yes/No strings from the registry */
3903 static BOOL
get_yesno_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3905 if (!ptr_param
) return FALSE
;
3907 if (!entry
->hdr
.loaded
)
3910 if (load_entry( &entry
->hdr
, buf
, sizeof(buf
) )) entry
->bool.val
= !wcsicmp( yesW
, buf
);
3912 *(UINT
*)ptr_param
= entry
->bool.val
;
3916 /* set a bool parameter using Yes/No strings from the registry */
3917 static BOOL
set_yesno_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3919 const WCHAR
*str
= int_param
? yesW
: noW
;
3921 if (!save_entry_string( &entry
->hdr
, str
, flags
)) return FALSE
;
3922 entry
->bool.val
= int_param
!= 0;
3923 entry
->hdr
.loaded
= TRUE
;
3927 /* initialize a bool parameter using Yes/No strings */
3928 static BOOL
init_yesno_entry( union sysparam_all_entry
*entry
)
3930 return init_entry_string( &entry
->hdr
, entry
->bool.val
? yesW
: noW
);
3933 /* load a dword (binary) parameter from the registry */
3934 static BOOL
get_dword_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3936 if (!ptr_param
) return FALSE
;
3938 if (!entry
->hdr
.loaded
)
3941 if (load_entry( &entry
->hdr
, &val
, sizeof(val
) ) == sizeof(DWORD
)) entry
->dword
.val
= val
;
3943 *(DWORD
*)ptr_param
= entry
->dword
.val
;
3947 /* set a dword (binary) parameter in the registry */
3948 static BOOL
set_dword_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3950 DWORD val
= PtrToUlong( ptr_param
);
3952 if (!save_entry( &entry
->hdr
, &val
, sizeof(val
), REG_DWORD
, flags
)) return FALSE
;
3953 entry
->dword
.val
= val
;
3954 entry
->hdr
.loaded
= TRUE
;
3958 /* initialize a dword parameter */
3959 static BOOL
init_dword_entry( union sysparam_all_entry
*entry
)
3961 return init_entry( &entry
->hdr
, &entry
->dword
.val
, sizeof(entry
->dword
.val
), REG_DWORD
);
3964 /* load an RGB parameter from the registry */
3965 static BOOL
get_rgb_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3967 if (!ptr_param
) return FALSE
;
3969 if (!entry
->hdr
.loaded
)
3973 if (load_entry( &entry
->hdr
, buf
, sizeof(buf
) ))
3976 WCHAR
*end
, *str
= buf
;
3978 r
= wcstoul( str
, &end
, 10 );
3979 if (end
== str
|| !*end
) goto done
;
3981 g
= wcstoul( str
, &end
, 10 );
3982 if (end
== str
|| !*end
) goto done
;
3984 b
= wcstoul( str
, &end
, 10 );
3985 if (end
== str
) goto done
;
3986 if (r
> 255 || g
> 255 || b
> 255) goto done
;
3987 entry
->rgb
.val
= RGB( r
, g
, b
);
3991 *(COLORREF
*)ptr_param
= entry
->rgb
.val
;
3995 /* set an RGB parameter in the registry */
3996 static BOOL
set_rgb_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
4003 sprintf( buf
, "%u %u %u", GetRValue(int_param
), GetGValue(int_param
), GetBValue(int_param
) );
4004 asciiz_to_unicode( bufW
, buf
);
4005 if (!save_entry_string( &entry
->hdr
, bufW
, flags
)) return FALSE
;
4006 entry
->rgb
.val
= int_param
;
4007 entry
->hdr
.loaded
= TRUE
;
4008 if ((brush
= InterlockedExchangePointer( (void **)&entry
->rgb
.brush
, 0 )))
4010 make_gdi_object_system( brush
, FALSE
);
4011 NtGdiDeleteObjectApp( brush
);
4013 if ((pen
= InterlockedExchangePointer( (void **)&entry
->rgb
.pen
, 0 )))
4015 make_gdi_object_system( pen
, FALSE
);
4016 NtGdiDeleteObjectApp( pen
);
4021 /* initialize an RGB parameter */
4022 static BOOL
init_rgb_entry( union sysparam_all_entry
*entry
)
4027 sprintf( buf
, "%u %u %u", GetRValue(entry
->rgb
.val
), GetGValue(entry
->rgb
.val
),
4028 GetBValue(entry
->rgb
.val
) );
4029 asciiz_to_unicode( bufW
, buf
);
4030 return init_entry_string( &entry
->hdr
, bufW
);
4033 /* get a path parameter in the registry */
4034 static BOOL
get_path_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
4036 if (!ptr_param
) return FALSE
;
4038 if (!entry
->hdr
.loaded
)
4040 WCHAR buffer
[MAX_PATH
];
4042 if (load_entry( &entry
->hdr
, buffer
, sizeof(buffer
) ))
4043 lstrcpynW( entry
->path
.path
, buffer
, MAX_PATH
);
4045 lstrcpynW( ptr_param
, entry
->path
.path
, int_param
);
4049 /* set a path parameter in the registry */
4050 static BOOL
set_path_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
4052 WCHAR buffer
[MAX_PATH
];
4055 lstrcpynW( buffer
, ptr_param
, MAX_PATH
);
4056 ret
= save_entry_string( &entry
->hdr
, buffer
, flags
);
4059 lstrcpyW( entry
->path
.path
, buffer
);
4060 entry
->hdr
.loaded
= TRUE
;
4065 /* initialize a path parameter */
4066 static BOOL
init_path_entry( union sysparam_all_entry
*entry
)
4068 return init_entry_string( &entry
->hdr
, entry
->path
.path
);
4071 /* get a binary parameter in the registry */
4072 static BOOL
get_binary_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
4074 if (!ptr_param
) return FALSE
;
4076 if (!entry
->hdr
.loaded
)
4078 void *buffer
= malloc( entry
->bin
.size
);
4079 DWORD len
= load_entry( &entry
->hdr
, buffer
, entry
->bin
.size
);
4083 memcpy( entry
->bin
.ptr
, buffer
, entry
->bin
.size
);
4084 memset( (char *)entry
->bin
.ptr
+ len
, 0, entry
->bin
.size
- len
);
4088 memcpy( ptr_param
, entry
->bin
.ptr
, min( int_param
, entry
->bin
.size
) );
4092 /* set a binary parameter in the registry */
4093 static BOOL
set_binary_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
4096 void *buffer
= malloc( entry
->bin
.size
);
4098 memcpy( buffer
, entry
->bin
.ptr
, entry
->bin
.size
);
4099 memcpy( buffer
, ptr_param
, min( int_param
, entry
->bin
.size
));
4100 ret
= save_entry( &entry
->hdr
, buffer
, entry
->bin
.size
, REG_BINARY
, flags
);
4103 memcpy( entry
->bin
.ptr
, buffer
, entry
->bin
.size
);
4104 entry
->hdr
.loaded
= TRUE
;
4110 /* initialize a binary parameter */
4111 static BOOL
init_binary_entry( union sysparam_all_entry
*entry
)
4113 return init_entry( &entry
->hdr
, entry
->bin
.ptr
, entry
->bin
.size
, REG_BINARY
);
4116 static void logfont16to32( const LOGFONT16
*font16
, LPLOGFONTW font32
)
4118 font32
->lfHeight
= font16
->lfHeight
;
4119 font32
->lfWidth
= font16
->lfWidth
;
4120 font32
->lfEscapement
= font16
->lfEscapement
;
4121 font32
->lfOrientation
= font16
->lfOrientation
;
4122 font32
->lfWeight
= font16
->lfWeight
;
4123 font32
->lfItalic
= font16
->lfItalic
;
4124 font32
->lfUnderline
= font16
->lfUnderline
;
4125 font32
->lfStrikeOut
= font16
->lfStrikeOut
;
4126 font32
->lfCharSet
= font16
->lfCharSet
;
4127 font32
->lfOutPrecision
= font16
->lfOutPrecision
;
4128 font32
->lfClipPrecision
= font16
->lfClipPrecision
;
4129 font32
->lfQuality
= font16
->lfQuality
;
4130 font32
->lfPitchAndFamily
= font16
->lfPitchAndFamily
;
4131 win32u_mbtowc( &ansi_cp
, font32
->lfFaceName
, LF_FACESIZE
, font16
->lfFaceName
,
4132 strlen( font16
->lfFaceName
));
4133 font32
->lfFaceName
[LF_FACESIZE
-1] = 0;
4136 static void get_real_fontname( LOGFONTW
*lf
, WCHAR fullname
[LF_FACESIZE
] )
4138 struct font_enum_entry enum_entry
;
4139 ULONG count
= sizeof(enum_entry
);
4142 hdc
= get_display_dc();
4143 NtGdiEnumFonts( hdc
, 0, 0, lstrlenW( lf
->lfFaceName
), lf
->lfFaceName
, lf
->lfCharSet
,
4144 &count
, &enum_entry
);
4145 release_display_dc( hdc
);
4148 lstrcpyW( fullname
, enum_entry
.lf
.elfFullName
);
4150 lstrcpyW( fullname
, lf
->lfFaceName
);
4153 LONG
get_char_dimensions( HDC hdc
, TEXTMETRICW
*metric
, int *height
)
4156 static const WCHAR abcdW
[] =
4157 {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
4158 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
4159 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
4161 if (metric
&& !NtGdiGetTextMetricsW( hdc
, metric
, 0 )) return 0;
4163 if (!NtGdiGetTextExtentExW( hdc
, abcdW
, ARRAYSIZE(abcdW
), 0, NULL
, NULL
, &sz
, 0 ))
4166 if (height
) *height
= sz
.cy
;
4167 return (sz
.cx
/ 26 + 1) / 2;
4170 /* get text metrics and/or "average" char width of the specified logfont
4171 * for the specified dc */
4172 static void get_text_metr_size( HDC hdc
, LOGFONTW
*lf
, TEXTMETRICW
*metric
, UINT
*psz
)
4174 HFONT hfont
, hfontsav
;
4177 if (!metric
) metric
= &tm
;
4178 hfont
= NtGdiHfontCreate( lf
, sizeof(*lf
), 0, 0, NULL
);
4179 if (!hfont
|| !(hfontsav
= NtGdiSelectFont( hdc
, hfont
)))
4181 metric
->tmHeight
= -1;
4183 if (hfont
) NtGdiDeleteObjectApp( hfont
);
4186 ret
= get_char_dimensions( hdc
, metric
, NULL
);
4187 if (psz
) *psz
= ret
? ret
: 10;
4188 NtGdiSelectFont( hdc
, hfontsav
);
4189 NtGdiDeleteObjectApp( hfont
);
4192 DWORD
get_dialog_base_units(void)
4200 if ((hdc
= NtUserGetDC( 0 )))
4202 cx
= get_char_dimensions( hdc
, NULL
, &cy
);
4203 NtUserReleaseDC( 0, hdc
);
4205 TRACE( "base units = %d,%d\n", cx
, cy
);
4208 return MAKELONG( muldiv( cx
, get_system_dpi(), USER_DEFAULT_SCREEN_DPI
),
4209 muldiv( cy
, get_system_dpi(), USER_DEFAULT_SCREEN_DPI
));
4212 /* adjust some of the raw values found in the registry */
4213 static void normalize_nonclientmetrics( NONCLIENTMETRICSW
*pncm
)
4216 HDC hdc
= get_display_dc();
4218 if( pncm
->iBorderWidth
< 1) pncm
->iBorderWidth
= 1;
4219 if( pncm
->iCaptionWidth
< 8) pncm
->iCaptionWidth
= 8;
4220 if( pncm
->iScrollWidth
< 8) pncm
->iScrollWidth
= 8;
4221 if( pncm
->iScrollHeight
< 8) pncm
->iScrollHeight
= 8;
4223 /* adjust some heights to the corresponding font */
4224 get_text_metr_size( hdc
, &pncm
->lfMenuFont
, &tm
, NULL
);
4225 pncm
->iMenuHeight
= max( pncm
->iMenuHeight
, 2 + tm
.tmHeight
+ tm
.tmExternalLeading
);
4226 get_text_metr_size( hdc
, &pncm
->lfCaptionFont
, &tm
, NULL
);
4227 pncm
->iCaptionHeight
= max( pncm
->iCaptionHeight
, 2 + tm
.tmHeight
);
4228 get_text_metr_size( hdc
, &pncm
->lfSmCaptionFont
, &tm
, NULL
);
4229 pncm
->iSmCaptionHeight
= max( pncm
->iSmCaptionHeight
, 2 + tm
.tmHeight
);
4230 release_display_dc( hdc
);
4233 /* load a font (binary) parameter from the registry */
4234 static BOOL
get_font_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
4238 if (!ptr_param
) return FALSE
;
4240 if (!entry
->hdr
.loaded
)
4242 switch (load_entry( &entry
->hdr
, &font
, sizeof(font
) ))
4245 if (font
.lfHeight
> 0) /* positive height value means points ( inch/72 ) */
4246 font
.lfHeight
= -muldiv( font
.lfHeight
, USER_DEFAULT_SCREEN_DPI
, 72 );
4247 entry
->font
.val
= font
;
4249 case sizeof(LOGFONT16
): /* win9x-winME format */
4250 logfont16to32( (LOGFONT16
*)&font
, &entry
->font
.val
);
4251 if (entry
->font
.val
.lfHeight
> 0)
4252 entry
->font
.val
.lfHeight
= -muldiv( entry
->font
.val
.lfHeight
, USER_DEFAULT_SCREEN_DPI
, 72 );
4255 WARN( "Unknown format in key %s value %s\n",
4256 debugstr_a( parameter_key_names
[entry
->hdr
.base_key
] ),
4257 debugstr_a( entry
->hdr
.regval
));
4259 case 0: /* use the default GUI font */
4260 NtGdiExtGetObjectW( GetStockObject( DEFAULT_GUI_FONT
), sizeof(font
), &font
);
4261 font
.lfHeight
= map_from_system_dpi( font
.lfHeight
);
4262 font
.lfWeight
= entry
->font
.weight
;
4263 entry
->font
.val
= font
;
4266 get_real_fontname( &entry
->font
.val
, entry
->font
.fullname
);
4267 entry
->hdr
.loaded
= TRUE
;
4269 font
= entry
->font
.val
;
4270 font
.lfHeight
= map_to_dpi( font
.lfHeight
, dpi
);
4271 lstrcpyW( font
.lfFaceName
, entry
->font
.fullname
);
4272 *(LOGFONTW
*)ptr_param
= font
;
4276 /* set a font (binary) parameter in the registry */
4277 static BOOL
set_font_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
4282 memcpy( &font
, ptr_param
, sizeof(font
) );
4283 /* zero pad the end of lfFaceName so we don't save uninitialised data */
4284 for (ptr
= font
.lfFaceName
; ptr
< font
.lfFaceName
+ LF_FACESIZE
&& *ptr
; ptr
++);
4285 if (ptr
< font
.lfFaceName
+ LF_FACESIZE
)
4286 memset( ptr
, 0, (font
.lfFaceName
+ LF_FACESIZE
- ptr
) * sizeof(WCHAR
) );
4287 if (font
.lfHeight
< 0) font
.lfHeight
= map_from_system_dpi( font
.lfHeight
);
4289 if (!save_entry( &entry
->hdr
, &font
, sizeof(font
), REG_BINARY
, flags
)) return FALSE
;
4290 entry
->font
.val
= font
;
4291 get_real_fontname( &entry
->font
.val
, entry
->font
.fullname
);
4292 entry
->hdr
.loaded
= TRUE
;
4296 /* initialize a font (binary) parameter */
4297 static BOOL
init_font_entry( union sysparam_all_entry
*entry
)
4299 NtGdiExtGetObjectW( GetStockObject( DEFAULT_GUI_FONT
), sizeof(entry
->font
.val
), &entry
->font
.val
);
4300 entry
->font
.val
.lfHeight
= map_from_system_dpi( entry
->font
.val
.lfHeight
);
4301 entry
->font
.val
.lfWeight
= entry
->font
.weight
;
4302 get_real_fontname( &entry
->font
.val
, entry
->font
.fullname
);
4303 return init_entry( &entry
->hdr
, &entry
->font
.val
, sizeof(entry
->font
.val
), REG_BINARY
);
4306 /* get a user pref parameter in the registry */
4307 static BOOL
get_userpref_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
4309 union sysparam_all_entry
*parent_entry
= entry
->pref
.parent
;
4312 if (!ptr_param
) return FALSE
;
4314 if (!parent_entry
->hdr
.get( parent_entry
, sizeof(prefs
), prefs
, dpi
)) return FALSE
;
4315 *(BOOL
*)ptr_param
= (prefs
[entry
->pref
.offset
] & entry
->pref
.mask
) != 0;
4319 /* set a user pref parameter in the registry */
4320 static BOOL
set_userpref_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
4322 union sysparam_all_entry
*parent_entry
= entry
->pref
.parent
;
4325 parent_entry
->hdr
.loaded
= FALSE
; /* force loading it again */
4326 if (!parent_entry
->hdr
.get( parent_entry
, sizeof(prefs
), prefs
, get_system_dpi() )) return FALSE
;
4328 if (PtrToUlong( ptr_param
)) prefs
[entry
->pref
.offset
] |= entry
->pref
.mask
;
4329 else prefs
[entry
->pref
.offset
] &= ~entry
->pref
.mask
;
4331 return parent_entry
->hdr
.set( parent_entry
, sizeof(prefs
), prefs
, flags
);
4334 static BOOL
get_entry_dpi( void *ptr
, UINT int_param
, void *ptr_param
, UINT dpi
)
4336 union sysparam_all_entry
*entry
= ptr
;
4337 return entry
->hdr
.get( entry
, int_param
, ptr_param
, dpi
);
4340 static BOOL
get_entry( void *ptr
, UINT int_param
, void *ptr_param
)
4342 return get_entry_dpi( ptr
, int_param
, ptr_param
, get_system_dpi() );
4345 static BOOL
set_entry( void *ptr
, UINT int_param
, void *ptr_param
, UINT flags
)
4347 union sysparam_all_entry
*entry
= ptr
;
4348 return entry
->hdr
.set( entry
, int_param
, ptr_param
, flags
);
4351 #define UINT_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
4352 { .uint = { { get_uint_entry, set_uint_entry, init_uint_entry, base, reg }, (val) } }
4354 #define UINT_ENTRY_MIRROR(name,val,base,reg,mirror_base) union sysparam_all_entry entry_##name = \
4355 { .uint = { { get_uint_entry, set_uint_entry, init_uint_entry, base, reg, mirror_base, reg }, (val) } }
4357 #define INT_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
4358 { .uint = { { get_uint_entry, set_int_entry, init_int_entry, base, reg }, (val) } }
4360 #define BOOL_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
4361 { .bool = { { get_bool_entry, set_bool_entry, init_bool_entry, base, reg }, (val) } }
4363 #define BOOL_ENTRY_MIRROR(name,val,base,reg,mirror_base) union sysparam_all_entry entry_##name = \
4364 { .bool = { { get_bool_entry, set_bool_entry, init_bool_entry, base, reg, mirror_base, reg }, (val) } }
4366 #define TWIPS_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
4367 { .uint = { { get_twips_entry, set_twips_entry, init_int_entry, base, reg }, (val) } }
4369 #define YESNO_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
4370 { .bool = { { get_yesno_entry, set_yesno_entry, init_yesno_entry, base, reg }, (val) } }
4372 #define DWORD_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
4373 { .dword = { { get_dword_entry, set_dword_entry, init_dword_entry, base, reg }, (val) } }
4375 #define BINARY_ENTRY(name,data,base,reg) union sysparam_all_entry entry_##name = \
4376 { .bin = { { get_binary_entry, set_binary_entry, init_binary_entry, base, reg }, data, sizeof(data) } }
4378 #define PATH_ENTRY(name,base,reg,buffer) union sysparam_all_entry entry_##name = \
4379 { .path = { { get_path_entry, set_path_entry, init_path_entry, base, reg }, buffer } }
4381 #define FONT_ENTRY(name,weight,base,reg) union sysparam_all_entry entry_##name = \
4382 { .font = { { get_font_entry, set_font_entry, init_font_entry, base, reg }, (weight) } }
4384 #define USERPREF_ENTRY(name,offset,mask) union sysparam_all_entry entry_##name = \
4385 { .pref = { { get_userpref_entry, set_userpref_entry }, &entry_USERPREFERENCESMASK, (offset), (mask) } }
4387 static UINT_ENTRY( DRAGWIDTH
, 4, DESKTOP_KEY
, "DragWidth" );
4388 static UINT_ENTRY( DRAGHEIGHT
, 4, DESKTOP_KEY
, "DragHeight" );
4389 static UINT_ENTRY( DOUBLECLICKTIME
, 500, MOUSE_KEY
, "DoubleClickSpeed" );
4390 static UINT_ENTRY( FONTSMOOTHING
, 2, DESKTOP_KEY
, "FontSmoothing" );
4391 static UINT_ENTRY( GRIDGRANULARITY
, 0, DESKTOP_KEY
, "GridGranularity" );
4392 static UINT_ENTRY( KEYBOARDDELAY
, 1, KEYBOARD_KEY
, "KeyboardDelay" );
4393 static UINT_ENTRY( KEYBOARDSPEED
, 31, KEYBOARD_KEY
, "KeyboardSpeed" );
4394 static UINT_ENTRY( MENUSHOWDELAY
, 400, DESKTOP_KEY
, "MenuShowDelay" );
4395 static UINT_ENTRY( MINARRANGE
, ARW_HIDE
, METRICS_KEY
, "MinArrange" );
4396 static UINT_ENTRY( MINHORZGAP
, 0, METRICS_KEY
, "MinHorzGap" );
4397 static UINT_ENTRY( MINVERTGAP
, 0, METRICS_KEY
, "MinVertGap" );
4398 static UINT_ENTRY( MINWIDTH
, 154, METRICS_KEY
, "MinWidth" );
4399 static UINT_ENTRY( MOUSEHOVERHEIGHT
, 4, MOUSE_KEY
, "MouseHoverHeight" );
4400 static UINT_ENTRY( MOUSEHOVERTIME
, 400, MOUSE_KEY
, "MouseHoverTime" );
4401 static UINT_ENTRY( MOUSEHOVERWIDTH
, 4, MOUSE_KEY
, "MouseHoverWidth" );
4402 static UINT_ENTRY( MOUSESPEED
, 10, MOUSE_KEY
, "MouseSensitivity" );
4403 static UINT_ENTRY( MOUSETRAILS
, 0, MOUSE_KEY
, "MouseTrails" );
4404 static UINT_ENTRY( SCREENSAVETIMEOUT
, 300, DESKTOP_KEY
, "ScreenSaveTimeOut" );
4405 static UINT_ENTRY( WHEELSCROLLCHARS
, 3, DESKTOP_KEY
, "WheelScrollChars" );
4406 static UINT_ENTRY( WHEELSCROLLLINES
, 3, DESKTOP_KEY
, "WheelScrollLines" );
4407 static UINT_ENTRY_MIRROR( DOUBLECLKHEIGHT
, 4, MOUSE_KEY
, "DoubleClickHeight", DESKTOP_KEY
);
4408 static UINT_ENTRY_MIRROR( DOUBLECLKWIDTH
, 4, MOUSE_KEY
, "DoubleClickWidth", DESKTOP_KEY
);
4409 static UINT_ENTRY_MIRROR( MENUDROPALIGNMENT
, 0, DESKTOP_KEY
, "MenuDropAlignment", VERSION_KEY
);
4411 static INT_ENTRY( MOUSETHRESHOLD1
, 6, MOUSE_KEY
, "MouseThreshold1" );
4412 static INT_ENTRY( MOUSETHRESHOLD2
, 10, MOUSE_KEY
, "MouseThreshold2" );
4413 static INT_ENTRY( MOUSEACCELERATION
, 1, MOUSE_KEY
, "MouseSpeed" );
4415 static BOOL_ENTRY( BLOCKSENDINPUTRESETS
, FALSE
, DESKTOP_KEY
, "BlockSendInputResets" );
4416 static BOOL_ENTRY( DRAGFULLWINDOWS
, FALSE
, DESKTOP_KEY
, "DragFullWindows" );
4417 static BOOL_ENTRY( KEYBOARDPREF
, TRUE
, KEYBOARDPREF_KEY
, "On" );
4418 static BOOL_ENTRY( LOWPOWERACTIVE
, FALSE
, DESKTOP_KEY
, "LowPowerActive" );
4419 static BOOL_ENTRY( MOUSEBUTTONSWAP
, FALSE
, MOUSE_KEY
, "SwapMouseButtons" );
4420 static BOOL_ENTRY( POWEROFFACTIVE
, FALSE
, DESKTOP_KEY
, "PowerOffActive" );
4421 static BOOL_ENTRY( SCREENREADER
, FALSE
, SCREENREADER_KEY
, "On" );
4422 static BOOL_ENTRY( SCREENSAVEACTIVE
, TRUE
, DESKTOP_KEY
, "ScreenSaveActive" );
4423 static BOOL_ENTRY( SCREENSAVERRUNNING
, FALSE
, DESKTOP_KEY
, "WINE_ScreenSaverRunning" ); /* FIXME - real value */
4424 static BOOL_ENTRY( SHOWSOUNDS
, FALSE
, SHOWSOUNDS_KEY
, "On" );
4425 static BOOL_ENTRY( SNAPTODEFBUTTON
, FALSE
, MOUSE_KEY
, "SnapToDefaultButton" );
4426 static BOOL_ENTRY_MIRROR( ICONTITLEWRAP
, TRUE
, DESKTOP_KEY
, "IconTitleWrap", METRICS_KEY
);
4427 static BOOL_ENTRY( AUDIODESC_ON
, FALSE
, AUDIODESC_KEY
, "On" );
4429 static TWIPS_ENTRY( BORDER
, -15, METRICS_KEY
, "BorderWidth" );
4430 static TWIPS_ENTRY( CAPTIONHEIGHT
, -270, METRICS_KEY
, "CaptionHeight" );
4431 static TWIPS_ENTRY( CAPTIONWIDTH
, -270, METRICS_KEY
, "CaptionWidth" );
4432 static TWIPS_ENTRY( ICONHORIZONTALSPACING
, -1125, METRICS_KEY
, "IconSpacing" );
4433 static TWIPS_ENTRY( ICONVERTICALSPACING
, -1125, METRICS_KEY
, "IconVerticalSpacing" );
4434 static TWIPS_ENTRY( MENUHEIGHT
, -270, METRICS_KEY
, "MenuHeight" );
4435 static TWIPS_ENTRY( MENUWIDTH
, -270, METRICS_KEY
, "MenuWidth" );
4436 static TWIPS_ENTRY( PADDEDBORDERWIDTH
, 0, METRICS_KEY
, "PaddedBorderWidth" );
4437 static TWIPS_ENTRY( SCROLLHEIGHT
, -240, METRICS_KEY
, "ScrollHeight" );
4438 static TWIPS_ENTRY( SCROLLWIDTH
, -240, METRICS_KEY
, "ScrollWidth" );
4439 static TWIPS_ENTRY( SMCAPTIONHEIGHT
, -225, METRICS_KEY
, "SmCaptionHeight" );
4440 static TWIPS_ENTRY( SMCAPTIONWIDTH
, -225, METRICS_KEY
, "SmCaptionWidth" );
4442 static YESNO_ENTRY( BEEP
, TRUE
, SOUND_KEY
, "Beep" );
4444 static DWORD_ENTRY( ACTIVEWINDOWTRACKING
, 0, MOUSE_KEY
, "ActiveWindowTracking" );
4445 static DWORD_ENTRY( ACTIVEWNDTRKTIMEOUT
, 0, DESKTOP_KEY
, "ActiveWndTrackTimeout" );
4446 static DWORD_ENTRY( CARETWIDTH
, 1, DESKTOP_KEY
, "CaretWidth" );
4447 static DWORD_ENTRY( DPISCALINGVER
, 0, DESKTOP_KEY
, "DpiScalingVer" );
4448 static DWORD_ENTRY( FOCUSBORDERHEIGHT
, 1, DESKTOP_KEY
, "FocusBorderHeight" );
4449 static DWORD_ENTRY( FOCUSBORDERWIDTH
, 1, DESKTOP_KEY
, "FocusBorderWidth" );
4450 static DWORD_ENTRY( FONTSMOOTHINGCONTRAST
, 0, DESKTOP_KEY
, "FontSmoothingGamma" );
4451 static DWORD_ENTRY( FONTSMOOTHINGORIENTATION
, FE_FONTSMOOTHINGORIENTATIONRGB
, DESKTOP_KEY
, "FontSmoothingOrientation" );
4452 static DWORD_ENTRY( FONTSMOOTHINGTYPE
, FE_FONTSMOOTHINGSTANDARD
, DESKTOP_KEY
, "FontSmoothingType" );
4453 static DWORD_ENTRY( FOREGROUNDFLASHCOUNT
, 3, DESKTOP_KEY
, "ForegroundFlashCount" );
4454 static DWORD_ENTRY( FOREGROUNDLOCKTIMEOUT
, 0, DESKTOP_KEY
, "ForegroundLockTimeout" );
4455 static DWORD_ENTRY( LOGPIXELS
, 0, DESKTOP_KEY
, "LogPixels" );
4456 static DWORD_ENTRY( MOUSECLICKLOCKTIME
, 1200, DESKTOP_KEY
, "ClickLockTime" );
4457 static DWORD_ENTRY( AUDIODESC_LOCALE
, 0, AUDIODESC_KEY
, "Locale" );
4459 static WCHAR desk_pattern_path
[MAX_PATH
];
4460 static WCHAR desk_wallpaper_path
[MAX_PATH
];
4461 static PATH_ENTRY( DESKPATTERN
, DESKTOP_KEY
, "Pattern", desk_pattern_path
);
4462 static PATH_ENTRY( DESKWALLPAPER
, DESKTOP_KEY
, "Wallpaper", desk_wallpaper_path
);
4464 static BYTE user_prefs
[8] = { 0x30, 0x00, 0x00, 0x80, 0x12, 0x00, 0x00, 0x00 };
4465 static BINARY_ENTRY( USERPREFERENCESMASK
, user_prefs
, DESKTOP_KEY
, "UserPreferencesMask" );
4467 static FONT_ENTRY( CAPTIONLOGFONT
, FW_BOLD
, METRICS_KEY
, "CaptionFont" );
4468 static FONT_ENTRY( ICONTITLELOGFONT
, FW_NORMAL
, METRICS_KEY
, "IconFont" );
4469 static FONT_ENTRY( MENULOGFONT
, FW_NORMAL
, METRICS_KEY
, "MenuFont" );
4470 static FONT_ENTRY( MESSAGELOGFONT
, FW_NORMAL
, METRICS_KEY
, "MessageFont" );
4471 static FONT_ENTRY( SMCAPTIONLOGFONT
, FW_NORMAL
, METRICS_KEY
, "SmCaptionFont" );
4472 static FONT_ENTRY( STATUSLOGFONT
, FW_NORMAL
, METRICS_KEY
, "StatusFont" );
4474 static USERPREF_ENTRY( MENUANIMATION
, 0, 0x02 );
4475 static USERPREF_ENTRY( COMBOBOXANIMATION
, 0, 0x04 );
4476 static USERPREF_ENTRY( LISTBOXSMOOTHSCROLLING
, 0, 0x08 );
4477 static USERPREF_ENTRY( GRADIENTCAPTIONS
, 0, 0x10 );
4478 static USERPREF_ENTRY( KEYBOARDCUES
, 0, 0x20 );
4479 static USERPREF_ENTRY( ACTIVEWNDTRKZORDER
, 0, 0x40 );
4480 static USERPREF_ENTRY( HOTTRACKING
, 0, 0x80 );
4481 static USERPREF_ENTRY( MENUFADE
, 1, 0x02 );
4482 static USERPREF_ENTRY( SELECTIONFADE
, 1, 0x04 );
4483 static USERPREF_ENTRY( TOOLTIPANIMATION
, 1, 0x08 );
4484 static USERPREF_ENTRY( TOOLTIPFADE
, 1, 0x10 );
4485 static USERPREF_ENTRY( CURSORSHADOW
, 1, 0x20 );
4486 static USERPREF_ENTRY( MOUSESONAR
, 1, 0x40 );
4487 static USERPREF_ENTRY( MOUSECLICKLOCK
, 1, 0x80 );
4488 static USERPREF_ENTRY( MOUSEVANISH
, 2, 0x01 );
4489 static USERPREF_ENTRY( FLATMENU
, 2, 0x02 );
4490 static USERPREF_ENTRY( DROPSHADOW
, 2, 0x04 );
4491 static USERPREF_ENTRY( UIEFFECTS
, 3, 0x80 );
4492 static USERPREF_ENTRY( DISABLEOVERLAPPEDCONTENT
, 4, 0x01 );
4493 static USERPREF_ENTRY( CLIENTAREAANIMATION
, 4, 0x02 );
4494 static USERPREF_ENTRY( CLEARTYPE
, 4, 0x10 );
4495 static USERPREF_ENTRY( SPEECHRECOGNITION
, 4, 0x20 );
4497 /* System parameter indexes */
4500 SPI_SETWORKAREA_IDX
,
4504 /* indicators whether system parameter value is loaded */
4505 static char spi_loaded
[SPI_INDEX_COUNT
];
4507 static struct sysparam_rgb_entry system_colors
[] =
4509 #define RGB_ENTRY(name,val,reg) { { get_rgb_entry, set_rgb_entry, init_rgb_entry, COLORS_KEY, reg }, (val) }
4510 RGB_ENTRY( COLOR_SCROLLBAR
, RGB(212, 208, 200), "Scrollbar" ),
4511 RGB_ENTRY( COLOR_BACKGROUND
, RGB(58, 110, 165), "Background" ),
4512 RGB_ENTRY( COLOR_ACTIVECAPTION
, RGB(10, 36, 106), "ActiveTitle" ),
4513 RGB_ENTRY( COLOR_INACTIVECAPTION
, RGB(128, 128, 128), "InactiveTitle" ),
4514 RGB_ENTRY( COLOR_MENU
, RGB(212, 208, 200), "Menu" ),
4515 RGB_ENTRY( COLOR_WINDOW
, RGB(255, 255, 255), "Window" ),
4516 RGB_ENTRY( COLOR_WINDOWFRAME
, RGB(0, 0, 0), "WindowFrame" ),
4517 RGB_ENTRY( COLOR_MENUTEXT
, RGB(0, 0, 0), "MenuText" ),
4518 RGB_ENTRY( COLOR_WINDOWTEXT
, RGB(0, 0, 0), "WindowText" ),
4519 RGB_ENTRY( COLOR_CAPTIONTEXT
, RGB(255, 255, 255), "TitleText" ),
4520 RGB_ENTRY( COLOR_ACTIVEBORDER
, RGB(212, 208, 200), "ActiveBorder" ),
4521 RGB_ENTRY( COLOR_INACTIVEBORDER
, RGB(212, 208, 200), "InactiveBorder" ),
4522 RGB_ENTRY( COLOR_APPWORKSPACE
, RGB(128, 128, 128), "AppWorkSpace" ),
4523 RGB_ENTRY( COLOR_HIGHLIGHT
, RGB(10, 36, 106), "Hilight" ),
4524 RGB_ENTRY( COLOR_HIGHLIGHTTEXT
, RGB(255, 255, 255), "HilightText" ),
4525 RGB_ENTRY( COLOR_BTNFACE
, RGB(212, 208, 200), "ButtonFace" ),
4526 RGB_ENTRY( COLOR_BTNSHADOW
, RGB(128, 128, 128), "ButtonShadow" ),
4527 RGB_ENTRY( COLOR_GRAYTEXT
, RGB(128, 128, 128), "GrayText" ),
4528 RGB_ENTRY( COLOR_BTNTEXT
, RGB(0, 0, 0), "ButtonText" ),
4529 RGB_ENTRY( COLOR_INACTIVECAPTIONTEXT
, RGB(212, 208, 200), "InactiveTitleText" ),
4530 RGB_ENTRY( COLOR_BTNHIGHLIGHT
, RGB(255, 255, 255), "ButtonHilight" ),
4531 RGB_ENTRY( COLOR_3DDKSHADOW
, RGB(64, 64, 64), "ButtonDkShadow" ),
4532 RGB_ENTRY( COLOR_3DLIGHT
, RGB(212, 208, 200), "ButtonLight" ),
4533 RGB_ENTRY( COLOR_INFOTEXT
, RGB(0, 0, 0), "InfoText" ),
4534 RGB_ENTRY( COLOR_INFOBK
, RGB(255, 255, 225), "InfoWindow" ),
4535 RGB_ENTRY( COLOR_ALTERNATEBTNFACE
, RGB(181, 181, 181), "ButtonAlternateFace" ),
4536 RGB_ENTRY( COLOR_HOTLIGHT
, RGB(0, 0, 200), "HotTrackingColor" ),
4537 RGB_ENTRY( COLOR_GRADIENTACTIVECAPTION
, RGB(166, 202, 240), "GradientActiveTitle" ),
4538 RGB_ENTRY( COLOR_GRADIENTINACTIVECAPTION
, RGB(192, 192, 192), "GradientInactiveTitle" ),
4539 RGB_ENTRY( COLOR_MENUHILIGHT
, RGB(10, 36, 106), "MenuHilight" ),
4540 RGB_ENTRY( COLOR_MENUBAR
, RGB(212, 208, 200), "MenuBar" )
4544 /* entries that are initialized by default in the registry */
4545 static union sysparam_all_entry
* const default_entries
[] =
4547 (union sysparam_all_entry
*)&entry_ACTIVEWINDOWTRACKING
,
4548 (union sysparam_all_entry
*)&entry_ACTIVEWNDTRKTIMEOUT
,
4549 (union sysparam_all_entry
*)&entry_BEEP
,
4550 (union sysparam_all_entry
*)&entry_BLOCKSENDINPUTRESETS
,
4551 (union sysparam_all_entry
*)&entry_BORDER
,
4552 (union sysparam_all_entry
*)&entry_CAPTIONHEIGHT
,
4553 (union sysparam_all_entry
*)&entry_CAPTIONWIDTH
,
4554 (union sysparam_all_entry
*)&entry_CARETWIDTH
,
4555 (union sysparam_all_entry
*)&entry_DESKWALLPAPER
,
4556 (union sysparam_all_entry
*)&entry_DOUBLECLICKTIME
,
4557 (union sysparam_all_entry
*)&entry_DOUBLECLKHEIGHT
,
4558 (union sysparam_all_entry
*)&entry_DOUBLECLKWIDTH
,
4559 (union sysparam_all_entry
*)&entry_DRAGFULLWINDOWS
,
4560 (union sysparam_all_entry
*)&entry_DRAGHEIGHT
,
4561 (union sysparam_all_entry
*)&entry_DRAGWIDTH
,
4562 (union sysparam_all_entry
*)&entry_FOCUSBORDERHEIGHT
,
4563 (union sysparam_all_entry
*)&entry_FOCUSBORDERWIDTH
,
4564 (union sysparam_all_entry
*)&entry_FONTSMOOTHING
,
4565 (union sysparam_all_entry
*)&entry_FONTSMOOTHINGCONTRAST
,
4566 (union sysparam_all_entry
*)&entry_FONTSMOOTHINGORIENTATION
,
4567 (union sysparam_all_entry
*)&entry_FONTSMOOTHINGTYPE
,
4568 (union sysparam_all_entry
*)&entry_FOREGROUNDFLASHCOUNT
,
4569 (union sysparam_all_entry
*)&entry_FOREGROUNDLOCKTIMEOUT
,
4570 (union sysparam_all_entry
*)&entry_ICONHORIZONTALSPACING
,
4571 (union sysparam_all_entry
*)&entry_ICONTITLEWRAP
,
4572 (union sysparam_all_entry
*)&entry_ICONVERTICALSPACING
,
4573 (union sysparam_all_entry
*)&entry_KEYBOARDDELAY
,
4574 (union sysparam_all_entry
*)&entry_KEYBOARDPREF
,
4575 (union sysparam_all_entry
*)&entry_KEYBOARDSPEED
,
4576 (union sysparam_all_entry
*)&entry_LOWPOWERACTIVE
,
4577 (union sysparam_all_entry
*)&entry_MENUHEIGHT
,
4578 (union sysparam_all_entry
*)&entry_MENUSHOWDELAY
,
4579 (union sysparam_all_entry
*)&entry_MENUWIDTH
,
4580 (union sysparam_all_entry
*)&entry_MOUSEACCELERATION
,
4581 (union sysparam_all_entry
*)&entry_MOUSEBUTTONSWAP
,
4582 (union sysparam_all_entry
*)&entry_MOUSECLICKLOCKTIME
,
4583 (union sysparam_all_entry
*)&entry_MOUSEHOVERHEIGHT
,
4584 (union sysparam_all_entry
*)&entry_MOUSEHOVERTIME
,
4585 (union sysparam_all_entry
*)&entry_MOUSEHOVERWIDTH
,
4586 (union sysparam_all_entry
*)&entry_MOUSESPEED
,
4587 (union sysparam_all_entry
*)&entry_MOUSETHRESHOLD1
,
4588 (union sysparam_all_entry
*)&entry_MOUSETHRESHOLD2
,
4589 (union sysparam_all_entry
*)&entry_PADDEDBORDERWIDTH
,
4590 (union sysparam_all_entry
*)&entry_SCREENREADER
,
4591 (union sysparam_all_entry
*)&entry_SCROLLHEIGHT
,
4592 (union sysparam_all_entry
*)&entry_SCROLLWIDTH
,
4593 (union sysparam_all_entry
*)&entry_SHOWSOUNDS
,
4594 (union sysparam_all_entry
*)&entry_SMCAPTIONHEIGHT
,
4595 (union sysparam_all_entry
*)&entry_SMCAPTIONWIDTH
,
4596 (union sysparam_all_entry
*)&entry_SNAPTODEFBUTTON
,
4597 (union sysparam_all_entry
*)&entry_USERPREFERENCESMASK
,
4598 (union sysparam_all_entry
*)&entry_WHEELSCROLLCHARS
,
4599 (union sysparam_all_entry
*)&entry_WHEELSCROLLLINES
,
4600 (union sysparam_all_entry
*)&entry_AUDIODESC_LOCALE
,
4601 (union sysparam_all_entry
*)&entry_AUDIODESC_ON
,
4604 /***********************************************************************
4607 * Get a config key from either the app-specific or the default config
4609 static DWORD
get_config_key( HKEY defkey
, HKEY appkey
, const char *name
,
4610 WCHAR
*buffer
, DWORD size
)
4614 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)buf
;
4616 asciiz_to_unicode( nameW
, name
);
4618 if (appkey
&& query_reg_value( appkey
, nameW
, info
, sizeof(buf
) ))
4620 size
= min( info
->DataLength
, size
- sizeof(WCHAR
) );
4621 memcpy( buffer
, info
->Data
, size
);
4622 buffer
[size
/ sizeof(WCHAR
)] = 0;
4626 if (defkey
&& query_reg_value( defkey
, nameW
, info
, sizeof(buf
) ))
4628 size
= min( info
->DataLength
, size
- sizeof(WCHAR
) );
4629 memcpy( buffer
, info
->Data
, size
);
4630 buffer
[size
/ sizeof(WCHAR
)] = 0;
4634 return ERROR_FILE_NOT_FOUND
;
4637 void sysparams_init(void)
4639 WCHAR buffer
[MAX_PATH
+16], *p
, *appname
;
4640 DWORD i
, dispos
, dpi_scaling
;
4641 WCHAR layout
[KL_NAMELENGTH
];
4642 pthread_mutexattr_t attr
;
4643 HKEY hkey
, appkey
= 0;
4646 static const WCHAR software_wineW
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e'};
4647 static const WCHAR temporary_system_parametersW
[] =
4648 {'T','e','m','p','o','r','a','r','y',' ','S','y','s','t','e','m',' ',
4649 'P','a','r','a','m','e','t','e','r','s'};
4650 static const WCHAR oneW
[] = {'1',0};
4651 static const WCHAR kl_preloadW
[] =
4652 {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d'};
4653 static const WCHAR x11driverW
[] = {'\\','X','1','1',' ','D','r','i','v','e','r',0};
4655 pthread_mutexattr_init( &attr
);
4656 pthread_mutexattr_settype( &attr
, PTHREAD_MUTEX_RECURSIVE
);
4657 pthread_mutex_init( &user_mutex
, &attr
);
4658 pthread_mutexattr_destroy( &attr
);
4660 if ((hkey
= reg_create_key( hkcu_key
, kl_preloadW
, sizeof(kl_preloadW
), 0, NULL
)))
4662 if (NtUserGetKeyboardLayoutName( layout
))
4663 set_reg_value( hkey
, oneW
, REG_SZ
, (const BYTE
*)layout
,
4664 (lstrlenW(layout
) + 1) * sizeof(WCHAR
) );
4668 /* this one must be non-volatile */
4669 if (!(hkey
= reg_create_key( hkcu_key
, software_wineW
, sizeof(software_wineW
), 0, NULL
)))
4671 ERR("Can't create wine registry branch\n");
4675 /* @@ Wine registry key: HKCU\Software\Wine\Temporary System Parameters */
4676 if (!(volatile_base_key
= reg_create_key( hkey
, temporary_system_parametersW
,
4677 sizeof(temporary_system_parametersW
),
4678 REG_OPTION_VOLATILE
, &dispos
)))
4679 ERR("Can't create non-permanent wine registry branch\n");
4683 config_key
= reg_create_key( NULL
, config_keyW
, sizeof(config_keyW
), 0, NULL
);
4685 get_dword_entry( (union sysparam_all_entry
*)&entry_LOGPIXELS
, 0, &system_dpi
, 0 );
4686 if (!system_dpi
) /* check fallback key */
4688 static const WCHAR log_pixelsW
[] = {'L','o','g','P','i','x','e','l','s',0};
4689 static const WCHAR software_fontsW
[] =
4690 {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s'};
4692 if ((hkey
= reg_open_key( config_key
, software_fontsW
, sizeof(software_fontsW
) )))
4694 char buffer
[offsetof(KEY_VALUE_PARTIAL_INFORMATION
, Data
[sizeof(DWORD
)])];
4695 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
4697 if (query_reg_value( hkey
, log_pixelsW
, value
, sizeof(buffer
) ) && value
->Type
== REG_DWORD
)
4698 system_dpi
= *(const DWORD
*)value
->Data
;
4702 if (!system_dpi
) system_dpi
= USER_DEFAULT_SCREEN_DPI
;
4704 /* FIXME: what do the DpiScalingVer flags mean? */
4705 get_dword_entry( (union sysparam_all_entry
*)&entry_DPISCALINGVER
, 0, &dpi_scaling
, 0 );
4706 if (!dpi_scaling
) NtUserSetProcessDpiAwarenessContext( NTUSER_DPI_PER_MONITOR_AWARE
, 0 );
4708 if (volatile_base_key
&& dispos
== REG_CREATED_NEW_KEY
) /* first process, initialize entries */
4710 for (i
= 0; i
< ARRAY_SIZE( default_entries
); i
++)
4711 default_entries
[i
]->hdr
.init( default_entries
[i
] );
4714 /* @@ Wine registry key: HKCU\Software\Wine\X11 Driver */
4715 hkey
= reg_open_hkcu_key( "Software\\Wine\\X11 Driver" );
4717 /* open the app-specific key */
4719 appname
= NtCurrentTeb()->Peb
->ProcessParameters
->ImagePathName
.Buffer
;
4720 if ((p
= wcsrchr( appname
, '/' ))) appname
= p
+ 1;
4721 if ((p
= wcsrchr( appname
, '\\' ))) appname
= p
+ 1;
4722 len
= lstrlenW( appname
);
4724 if (len
&& len
< MAX_PATH
)
4729 for (i
= 0; appname
[i
]; i
++) buffer
[i
] = RtlDowncaseUnicodeChar( appname
[i
] );
4732 memcpy( appname
+ i
, x11driverW
, sizeof(x11driverW
) );
4734 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\X11 Driver */
4735 if ((tmpkey
= reg_open_hkcu_key( "Software\\Wine\\AppDefaults" )))
4737 appkey
= reg_open_key( tmpkey
, appname
, lstrlenW( appname
) * sizeof(WCHAR
) );
4742 #define IS_OPTION_TRUE(ch) \
4743 ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
4745 if (!get_config_key( hkey
, appkey
, "GrabPointer", buffer
, sizeof(buffer
) ))
4746 grab_pointer
= IS_OPTION_TRUE( buffer
[0] );
4747 if (!get_config_key( hkey
, appkey
, "GrabFullscreen", buffer
, sizeof(buffer
) ))
4748 grab_fullscreen
= IS_OPTION_TRUE( buffer
[0] );
4750 #undef IS_OPTION_TRUE
4753 static BOOL
update_desktop_wallpaper(void)
4755 /* FIXME: move implementation from user32 */
4756 entry_DESKWALLPAPER
.hdr
.loaded
= entry_DESKPATTERN
.hdr
.loaded
= FALSE
;
4760 /***********************************************************************
4761 * NtUserSystemParametersInfoForDpi (win32u.@)
4763 BOOL WINAPI
NtUserSystemParametersInfoForDpi( UINT action
, UINT val
, PVOID ptr
, UINT winini
, UINT dpi
)
4769 case SPI_GETICONTITLELOGFONT
:
4770 ret
= get_entry_dpi( &entry_ICONTITLELOGFONT
, val
, ptr
, dpi
);
4772 case SPI_GETNONCLIENTMETRICS
:
4774 NONCLIENTMETRICSW
*ncm
= ptr
;
4777 ret
= get_entry_dpi( &entry_BORDER
, 0, &ncm
->iBorderWidth
, dpi
) &&
4778 get_entry_dpi( &entry_SCROLLWIDTH
, 0, &ncm
->iScrollWidth
, dpi
) &&
4779 get_entry_dpi( &entry_SCROLLHEIGHT
, 0, &ncm
->iScrollHeight
, dpi
) &&
4780 get_entry_dpi( &entry_CAPTIONWIDTH
, 0, &ncm
->iCaptionWidth
, dpi
) &&
4781 get_entry_dpi( &entry_CAPTIONHEIGHT
, 0, &ncm
->iCaptionHeight
, dpi
) &&
4782 get_entry_dpi( &entry_CAPTIONLOGFONT
, 0, &ncm
->lfCaptionFont
, dpi
) &&
4783 get_entry_dpi( &entry_SMCAPTIONWIDTH
, 0, &ncm
->iSmCaptionWidth
, dpi
) &&
4784 get_entry_dpi( &entry_SMCAPTIONHEIGHT
, 0, &ncm
->iSmCaptionHeight
, dpi
) &&
4785 get_entry_dpi( &entry_SMCAPTIONLOGFONT
, 0, &ncm
->lfSmCaptionFont
, dpi
) &&
4786 get_entry_dpi( &entry_MENUWIDTH
, 0, &ncm
->iMenuWidth
, dpi
) &&
4787 get_entry_dpi( &entry_MENUHEIGHT
, 0, &ncm
->iMenuHeight
, dpi
) &&
4788 get_entry_dpi( &entry_MENULOGFONT
, 0, &ncm
->lfMenuFont
, dpi
) &&
4789 get_entry_dpi( &entry_STATUSLOGFONT
, 0, &ncm
->lfStatusFont
, dpi
) &&
4790 get_entry_dpi( &entry_MESSAGELOGFONT
, 0, &ncm
->lfMessageFont
, dpi
);
4791 if (ret
&& ncm
->cbSize
== sizeof(NONCLIENTMETRICSW
))
4792 ret
= get_entry_dpi( &entry_PADDEDBORDERWIDTH
, 0, &ncm
->iPaddedBorderWidth
, dpi
);
4793 normalize_nonclientmetrics( ncm
);
4796 case SPI_GETICONMETRICS
:
4798 ICONMETRICSW
*im
= ptr
;
4799 if (im
&& im
->cbSize
== sizeof(*im
))
4800 ret
= get_entry_dpi( &entry_ICONHORIZONTALSPACING
, 0, &im
->iHorzSpacing
, dpi
) &&
4801 get_entry_dpi( &entry_ICONVERTICALSPACING
, 0, &im
->iVertSpacing
, dpi
) &&
4802 get_entry_dpi( &entry_ICONTITLEWRAP
, 0, &im
->iTitleWrap
, dpi
) &&
4803 get_entry_dpi( &entry_ICONTITLELOGFONT
, 0, &im
->lfFont
, dpi
);
4807 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4813 /***********************************************************************
4814 * NtUserSystemParametersInfo (win32u.@)
4816 * Each system parameter has flag which shows whether the parameter
4817 * is loaded or not. Parameters, stored directly in SysParametersInfo are
4818 * loaded from registry only when they are requested and the flag is
4819 * "false", after the loading the flag is set to "true". On interprocess
4820 * notification of the parameter change the corresponding parameter flag is
4821 * set to "false". The parameter value will be reloaded when it is requested
4823 * Parameters, backed by or depend on GetSystemMetrics are processed
4824 * differently. These parameters are always loaded. They are reloaded right
4825 * away on interprocess change notification. We can't do lazy loading because
4826 * we don't want to complicate GetSystemMetrics.
4827 * Parameters backed by driver settings are read from corresponding setting.
4828 * On the parameter change request the setting is changed. Interprocess change
4829 * notifications are ignored.
4830 * When parameter value is updated the changed value is stored in permanent
4831 * registry branch if saving is requested. Otherwise it is stored
4832 * in temporary branch
4834 * Some SPI values can also be stored as Twips values in the registry,
4835 * don't forget the conversion!
4837 BOOL WINAPI
NtUserSystemParametersInfo( UINT action
, UINT val
, void *ptr
, UINT winini
)
4839 #define WINE_SPI_FIXME(x) \
4842 static BOOL warn = TRUE; \
4846 FIXME( "Unimplemented action: %u (%s)\n", x, #x ); \
4849 RtlSetLastWin32Error( ERROR_INVALID_SPI_VALUE ); \
4852 #define WINE_SPI_WARN(x) \
4854 WARN( "Ignored action: %u (%s)\n", x, #x ); \
4858 BOOL ret
= user_driver
->pSystemParametersInfo( action
, val
, ptr
, winini
);
4859 unsigned spi_idx
= 0;
4861 if (!ret
) switch (action
)
4864 ret
= get_entry( &entry_BEEP
, val
, ptr
);
4867 ret
= set_entry( &entry_BEEP
, val
, ptr
, winini
);
4870 ret
= get_entry( &entry_MOUSETHRESHOLD1
, val
, (INT
*)ptr
) &&
4871 get_entry( &entry_MOUSETHRESHOLD2
, val
, (INT
*)ptr
+ 1 ) &&
4872 get_entry( &entry_MOUSEACCELERATION
, val
, (INT
*)ptr
+ 2 );
4875 ret
= set_entry( &entry_MOUSETHRESHOLD1
, ((INT
*)ptr
)[0], ptr
, winini
) &&
4876 set_entry( &entry_MOUSETHRESHOLD2
, ((INT
*)ptr
)[1], ptr
, winini
) &&
4877 set_entry( &entry_MOUSEACCELERATION
, ((INT
*)ptr
)[2], ptr
, winini
);
4880 ret
= get_entry( &entry_BORDER
, val
, ptr
);
4881 if (*(INT
*)ptr
< 1) *(INT
*)ptr
= 1;
4884 ret
= set_entry( &entry_BORDER
, val
, ptr
, winini
);
4886 case SPI_GETKEYBOARDSPEED
:
4887 ret
= get_entry( &entry_KEYBOARDSPEED
, val
, ptr
);
4889 case SPI_SETKEYBOARDSPEED
:
4890 if (val
> 31) val
= 31;
4891 ret
= set_entry( &entry_KEYBOARDSPEED
, val
, ptr
, winini
);
4894 WINE_SPI_WARN(SPI_LANGDRIVER
); /* not implemented in Windows */
4896 case SPI_ICONHORIZONTALSPACING
:
4898 ret
= get_entry( &entry_ICONHORIZONTALSPACING
, val
, ptr
);
4901 int min_val
= map_to_dpi( 32, get_system_dpi() );
4902 ret
= set_entry( &entry_ICONHORIZONTALSPACING
, max( min_val
, val
), ptr
, winini
);
4905 case SPI_GETSCREENSAVETIMEOUT
:
4906 ret
= get_entry( &entry_SCREENSAVETIMEOUT
, val
, ptr
);
4908 case SPI_SETSCREENSAVETIMEOUT
:
4909 ret
= set_entry( &entry_SCREENSAVETIMEOUT
, val
, ptr
, winini
);
4911 case SPI_GETSCREENSAVEACTIVE
:
4912 ret
= get_entry( &entry_SCREENSAVEACTIVE
, val
, ptr
);
4914 case SPI_SETSCREENSAVEACTIVE
:
4915 ret
= set_entry( &entry_SCREENSAVEACTIVE
, val
, ptr
, winini
);
4917 case SPI_GETGRIDGRANULARITY
:
4918 ret
= get_entry( &entry_GRIDGRANULARITY
, val
, ptr
);
4920 case SPI_SETGRIDGRANULARITY
:
4921 ret
= set_entry( &entry_GRIDGRANULARITY
, val
, ptr
, winini
);
4923 case SPI_SETDESKWALLPAPER
:
4924 if (!ptr
|| set_entry( &entry_DESKWALLPAPER
, val
, ptr
, winini
))
4925 ret
= update_desktop_wallpaper();
4927 case SPI_SETDESKPATTERN
:
4928 if (!ptr
|| set_entry( &entry_DESKPATTERN
, val
, ptr
, winini
))
4929 ret
= update_desktop_wallpaper();
4931 case SPI_GETKEYBOARDDELAY
:
4932 ret
= get_entry( &entry_KEYBOARDDELAY
, val
, ptr
);
4934 case SPI_SETKEYBOARDDELAY
:
4935 ret
= set_entry( &entry_KEYBOARDDELAY
, val
, ptr
, winini
);
4937 case SPI_ICONVERTICALSPACING
:
4939 ret
= get_entry( &entry_ICONVERTICALSPACING
, val
, ptr
);
4942 int min_val
= map_to_dpi( 32, get_system_dpi() );
4943 ret
= set_entry( &entry_ICONVERTICALSPACING
, max( min_val
, val
), ptr
, winini
);
4946 case SPI_GETICONTITLEWRAP
:
4947 ret
= get_entry( &entry_ICONTITLEWRAP
, val
, ptr
);
4949 case SPI_SETICONTITLEWRAP
:
4950 ret
= set_entry( &entry_ICONTITLEWRAP
, val
, ptr
, winini
);
4952 case SPI_GETMENUDROPALIGNMENT
:
4953 ret
= get_entry( &entry_MENUDROPALIGNMENT
, val
, ptr
);
4955 case SPI_SETMENUDROPALIGNMENT
:
4956 ret
= set_entry( &entry_MENUDROPALIGNMENT
, val
, ptr
, winini
);
4958 case SPI_SETDOUBLECLKWIDTH
:
4959 ret
= set_entry( &entry_DOUBLECLKWIDTH
, val
, ptr
, winini
);
4961 case SPI_SETDOUBLECLKHEIGHT
:
4962 ret
= set_entry( &entry_DOUBLECLKHEIGHT
, val
, ptr
, winini
);
4964 case SPI_GETICONTITLELOGFONT
:
4965 ret
= get_entry( &entry_ICONTITLELOGFONT
, val
, ptr
);
4967 case SPI_SETDOUBLECLICKTIME
:
4968 ret
= set_entry( &entry_DOUBLECLICKTIME
, val
, ptr
, winini
);
4970 case SPI_SETMOUSEBUTTONSWAP
:
4971 ret
= set_entry( &entry_MOUSEBUTTONSWAP
, val
, ptr
, winini
);
4973 case SPI_SETICONTITLELOGFONT
:
4974 ret
= set_entry( &entry_ICONTITLELOGFONT
, val
, ptr
, winini
);
4976 case SPI_GETFASTTASKSWITCH
:
4977 if (!ptr
) return FALSE
;
4978 *(BOOL
*)ptr
= TRUE
;
4981 case SPI_SETFASTTASKSWITCH
:
4982 /* the action is disabled */
4985 case SPI_SETDRAGFULLWINDOWS
:
4986 ret
= set_entry( &entry_DRAGFULLWINDOWS
, val
, ptr
, winini
);
4988 case SPI_GETDRAGFULLWINDOWS
:
4989 ret
= get_entry( &entry_DRAGFULLWINDOWS
, val
, ptr
);
4991 case SPI_GETNONCLIENTMETRICS
:
4993 NONCLIENTMETRICSW
*nm
= ptr
;
4996 if (!ptr
) return FALSE
;
4998 ret
= get_entry( &entry_BORDER
, 0, &nm
->iBorderWidth
) &&
4999 get_entry( &entry_PADDEDBORDERWIDTH
, 0, &padded_border
) &&
5000 get_entry( &entry_SCROLLWIDTH
, 0, &nm
->iScrollWidth
) &&
5001 get_entry( &entry_SCROLLHEIGHT
, 0, &nm
->iScrollHeight
) &&
5002 get_entry( &entry_CAPTIONWIDTH
, 0, &nm
->iCaptionWidth
) &&
5003 get_entry( &entry_CAPTIONHEIGHT
, 0, &nm
->iCaptionHeight
) &&
5004 get_entry( &entry_CAPTIONLOGFONT
, 0, &nm
->lfCaptionFont
) &&
5005 get_entry( &entry_SMCAPTIONWIDTH
, 0, &nm
->iSmCaptionWidth
) &&
5006 get_entry( &entry_SMCAPTIONHEIGHT
, 0, &nm
->iSmCaptionHeight
) &&
5007 get_entry( &entry_SMCAPTIONLOGFONT
, 0, &nm
->lfSmCaptionFont
) &&
5008 get_entry( &entry_MENUWIDTH
, 0, &nm
->iMenuWidth
) &&
5009 get_entry( &entry_MENUHEIGHT
, 0, &nm
->iMenuHeight
) &&
5010 get_entry( &entry_MENULOGFONT
, 0, &nm
->lfMenuFont
) &&
5011 get_entry( &entry_STATUSLOGFONT
, 0, &nm
->lfStatusFont
) &&
5012 get_entry( &entry_MESSAGELOGFONT
, 0, &nm
->lfMessageFont
);
5015 nm
->iBorderWidth
+= padded_border
;
5016 if (nm
->cbSize
== sizeof(NONCLIENTMETRICSW
)) nm
->iPaddedBorderWidth
= 0;
5018 normalize_nonclientmetrics( nm
);
5021 case SPI_SETNONCLIENTMETRICS
:
5023 LPNONCLIENTMETRICSW nm
= ptr
;
5026 if (nm
&& (nm
->cbSize
== sizeof(NONCLIENTMETRICSW
) ||
5027 nm
->cbSize
== FIELD_OFFSET(NONCLIENTMETRICSW
, iPaddedBorderWidth
)))
5029 get_entry( &entry_PADDEDBORDERWIDTH
, 0, &padded_border
);
5031 ret
= set_entry( &entry_BORDER
, nm
->iBorderWidth
- padded_border
, NULL
, winini
) &&
5032 set_entry( &entry_SCROLLWIDTH
, nm
->iScrollWidth
, NULL
, winini
) &&
5033 set_entry( &entry_SCROLLHEIGHT
, nm
->iScrollHeight
, NULL
, winini
) &&
5034 set_entry( &entry_CAPTIONWIDTH
, nm
->iCaptionWidth
, NULL
, winini
) &&
5035 set_entry( &entry_CAPTIONHEIGHT
, nm
->iCaptionHeight
, NULL
, winini
) &&
5036 set_entry( &entry_SMCAPTIONWIDTH
, nm
->iSmCaptionWidth
, NULL
, winini
) &&
5037 set_entry( &entry_SMCAPTIONHEIGHT
, nm
->iSmCaptionHeight
, NULL
, winini
) &&
5038 set_entry( &entry_MENUWIDTH
, nm
->iMenuWidth
, NULL
, winini
) &&
5039 set_entry( &entry_MENUHEIGHT
, nm
->iMenuHeight
, NULL
, winini
) &&
5040 set_entry( &entry_MENULOGFONT
, 0, &nm
->lfMenuFont
, winini
) &&
5041 set_entry( &entry_CAPTIONLOGFONT
, 0, &nm
->lfCaptionFont
, winini
) &&
5042 set_entry( &entry_SMCAPTIONLOGFONT
, 0, &nm
->lfSmCaptionFont
, winini
) &&
5043 set_entry( &entry_STATUSLOGFONT
, 0, &nm
->lfStatusFont
, winini
) &&
5044 set_entry( &entry_MESSAGELOGFONT
, 0, &nm
->lfMessageFont
, winini
);
5048 case SPI_GETMINIMIZEDMETRICS
:
5050 MINIMIZEDMETRICS
*mm
= ptr
;
5051 if (mm
&& mm
->cbSize
== sizeof(*mm
)) {
5052 ret
= get_entry( &entry_MINWIDTH
, 0, &mm
->iWidth
) &&
5053 get_entry( &entry_MINHORZGAP
, 0, &mm
->iHorzGap
) &&
5054 get_entry( &entry_MINVERTGAP
, 0, &mm
->iVertGap
) &&
5055 get_entry( &entry_MINARRANGE
, 0, &mm
->iArrange
);
5056 mm
->iWidth
= max( 0, mm
->iWidth
);
5057 mm
->iHorzGap
= max( 0, mm
->iHorzGap
);
5058 mm
->iVertGap
= max( 0, mm
->iVertGap
);
5059 mm
->iArrange
&= 0x0f;
5063 case SPI_SETMINIMIZEDMETRICS
:
5065 MINIMIZEDMETRICS
*mm
= ptr
;
5066 if (mm
&& mm
->cbSize
== sizeof(*mm
))
5067 ret
= set_entry( &entry_MINWIDTH
, max( 0, mm
->iWidth
), NULL
, winini
) &&
5068 set_entry( &entry_MINHORZGAP
, max( 0, mm
->iHorzGap
), NULL
, winini
) &&
5069 set_entry( &entry_MINVERTGAP
, max( 0, mm
->iVertGap
), NULL
, winini
) &&
5070 set_entry( &entry_MINARRANGE
, mm
->iArrange
& 0x0f, NULL
, winini
);
5073 case SPI_GETICONMETRICS
:
5075 ICONMETRICSW
*icon
= ptr
;
5076 if(icon
&& icon
->cbSize
== sizeof(*icon
))
5078 ret
= get_entry( &entry_ICONHORIZONTALSPACING
, 0, &icon
->iHorzSpacing
) &&
5079 get_entry( &entry_ICONVERTICALSPACING
, 0, &icon
->iVertSpacing
) &&
5080 get_entry( &entry_ICONTITLEWRAP
, 0, &icon
->iTitleWrap
) &&
5081 get_entry( &entry_ICONTITLELOGFONT
, 0, &icon
->lfFont
);
5085 case SPI_SETICONMETRICS
:
5087 ICONMETRICSW
*icon
= ptr
;
5088 if (icon
&& icon
->cbSize
== sizeof(*icon
))
5089 ret
= set_entry( &entry_ICONVERTICALSPACING
, max(32,icon
->iVertSpacing
), NULL
, winini
) &&
5090 set_entry( &entry_ICONHORIZONTALSPACING
, max(32,icon
->iHorzSpacing
), NULL
, winini
) &&
5091 set_entry( &entry_ICONTITLEWRAP
, icon
->iTitleWrap
, NULL
, winini
) &&
5092 set_entry( &entry_ICONTITLELOGFONT
, 0, &icon
->lfFont
, winini
);
5095 case SPI_SETWORKAREA
:
5097 if (!ptr
) return FALSE
;
5098 spi_idx
= SPI_SETWORKAREA_IDX
;
5099 work_area
= *(RECT
*)ptr
;
5100 spi_loaded
[spi_idx
] = TRUE
;
5104 case SPI_GETWORKAREA
:
5106 if (!ptr
) return FALSE
;
5108 spi_idx
= SPI_SETWORKAREA_IDX
;
5109 if (!spi_loaded
[spi_idx
])
5111 struct monitor
*monitor
;
5113 if (!lock_display_devices()) return FALSE
;
5115 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
5117 if (!(monitor
->flags
& MONITORINFOF_PRIMARY
)) continue;
5118 work_area
= monitor
->rc_work
;
5122 unlock_display_devices();
5123 spi_loaded
[spi_idx
] = TRUE
;
5125 *(RECT
*)ptr
= map_dpi_rect( work_area
, system_dpi
, get_thread_dpi() );
5127 TRACE("work area %s\n", wine_dbgstr_rect( &work_area
));
5131 WINE_SPI_FIXME(SPI_SETPENWINDOWS
);
5133 case SPI_GETFILTERKEYS
:
5135 LPFILTERKEYS filter_keys
= ptr
;
5136 WARN("SPI_GETFILTERKEYS not fully implemented\n");
5137 if (filter_keys
&& filter_keys
->cbSize
== sizeof(FILTERKEYS
))
5139 /* Indicate that no FilterKeys feature available */
5140 filter_keys
->dwFlags
= 0;
5141 filter_keys
->iWaitMSec
= 0;
5142 filter_keys
->iDelayMSec
= 0;
5143 filter_keys
->iRepeatMSec
= 0;
5144 filter_keys
->iBounceMSec
= 0;
5149 WINE_SPI_FIXME(SPI_SETFILTERKEYS
);
5151 case SPI_GETTOGGLEKEYS
:
5153 LPTOGGLEKEYS toggle_keys
= ptr
;
5154 WARN("SPI_GETTOGGLEKEYS not fully implemented\n");
5155 if (toggle_keys
&& toggle_keys
->cbSize
== sizeof(TOGGLEKEYS
))
5157 /* Indicate that no ToggleKeys feature available */
5158 toggle_keys
->dwFlags
= 0;
5164 WINE_SPI_FIXME(SPI_SETTOGGLEKEYS
);
5166 case SPI_GETMOUSEKEYS
:
5168 MOUSEKEYS
*mouse_keys
= ptr
;
5169 WARN("SPI_GETMOUSEKEYS not fully implemented\n");
5170 if (mouse_keys
&& mouse_keys
->cbSize
== sizeof(MOUSEKEYS
))
5172 /* Indicate that no MouseKeys feature available */
5173 mouse_keys
->dwFlags
= 0;
5174 mouse_keys
->iMaxSpeed
= 360;
5175 mouse_keys
->iTimeToMaxSpeed
= 1000;
5176 mouse_keys
->iCtrlSpeed
= 0;
5177 mouse_keys
->dwReserved1
= 0;
5178 mouse_keys
->dwReserved2
= 0;
5184 WINE_SPI_FIXME(SPI_SETMOUSEKEYS
);
5186 case SPI_GETSHOWSOUNDS
:
5187 ret
= get_entry( &entry_SHOWSOUNDS
, val
, ptr
);
5189 case SPI_SETSHOWSOUNDS
:
5190 ret
= set_entry( &entry_SHOWSOUNDS
, val
, ptr
, winini
);
5192 case SPI_GETSTICKYKEYS
:
5194 STICKYKEYS
*sticky_keys
= ptr
;
5195 WARN("SPI_GETSTICKYKEYS not fully implemented\n");
5196 if (sticky_keys
&& sticky_keys
->cbSize
== sizeof(STICKYKEYS
))
5198 /* Indicate that no StickyKeys feature available */
5199 sticky_keys
->dwFlags
= 0;
5205 WINE_SPI_FIXME(SPI_SETSTICKYKEYS
);
5207 case SPI_GETACCESSTIMEOUT
:
5209 ACCESSTIMEOUT
*access_timeout
= ptr
;
5210 WARN("SPI_GETACCESSTIMEOUT not fully implemented\n");
5211 if (access_timeout
&& access_timeout
->cbSize
== sizeof(ACCESSTIMEOUT
))
5213 /* Indicate that no accessibility features timeout is available */
5214 access_timeout
->dwFlags
= 0;
5215 access_timeout
->iTimeOutMSec
= 0;
5221 WINE_SPI_FIXME(SPI_SETACCESSTIMEOUT
);
5223 case SPI_GETSERIALKEYS
:
5225 LPSERIALKEYSW serial_keys
= ptr
;
5226 WARN("SPI_GETSERIALKEYS not fully implemented\n");
5227 if (serial_keys
&& serial_keys
->cbSize
== sizeof(SERIALKEYSW
))
5229 /* Indicate that no SerialKeys feature available */
5230 serial_keys
->dwFlags
= 0;
5231 serial_keys
->lpszActivePort
= NULL
;
5232 serial_keys
->lpszPort
= NULL
;
5233 serial_keys
->iBaudRate
= 0;
5234 serial_keys
->iPortState
= 0;
5240 WINE_SPI_FIXME(SPI_SETSERIALKEYS
);
5242 case SPI_GETSOUNDSENTRY
:
5244 SOUNDSENTRYW
*sound_sentry
= ptr
;
5245 WARN("SPI_GETSOUNDSENTRY not fully implemented\n");
5246 if (sound_sentry
&& sound_sentry
->cbSize
== sizeof(SOUNDSENTRYW
))
5248 /* Indicate that no SoundSentry feature available */
5249 sound_sentry
->dwFlags
= 0;
5250 sound_sentry
->iFSTextEffect
= 0;
5251 sound_sentry
->iFSTextEffectMSec
= 0;
5252 sound_sentry
->iFSTextEffectColorBits
= 0;
5253 sound_sentry
->iFSGrafEffect
= 0;
5254 sound_sentry
->iFSGrafEffectMSec
= 0;
5255 sound_sentry
->iFSGrafEffectColor
= 0;
5256 sound_sentry
->iWindowsEffect
= 0;
5257 sound_sentry
->iWindowsEffectMSec
= 0;
5258 sound_sentry
->lpszWindowsEffectDLL
= 0;
5259 sound_sentry
->iWindowsEffectOrdinal
= 0;
5265 WINE_SPI_FIXME(SPI_SETSOUNDSENTRY
);
5267 case SPI_GETHIGHCONTRAST
:
5269 HIGHCONTRASTW
*high_contrast
= ptr
;
5270 WARN("SPI_GETHIGHCONTRAST not fully implemented\n");
5271 if (high_contrast
&& high_contrast
->cbSize
== sizeof(HIGHCONTRASTW
))
5273 /* Indicate that no high contrast feature available */
5274 high_contrast
->dwFlags
= 0;
5275 high_contrast
->lpszDefaultScheme
= NULL
;
5281 WINE_SPI_FIXME(SPI_SETHIGHCONTRAST
);
5283 case SPI_GETKEYBOARDPREF
:
5284 ret
= get_entry( &entry_KEYBOARDPREF
, val
, ptr
);
5286 case SPI_SETKEYBOARDPREF
:
5287 ret
= set_entry( &entry_KEYBOARDPREF
, val
, ptr
, winini
);
5289 case SPI_GETSCREENREADER
:
5290 ret
= get_entry( &entry_SCREENREADER
, val
, ptr
);
5292 case SPI_SETSCREENREADER
:
5293 ret
= set_entry( &entry_SCREENREADER
, val
, ptr
, winini
);
5296 case SPI_GETANIMATION
:
5298 ANIMATIONINFO
*anim_info
= ptr
;
5300 /* Tell it "disabled" */
5301 if (anim_info
&& anim_info
->cbSize
== sizeof(ANIMATIONINFO
))
5303 /* Minimize and restore animation is disabled (nonzero == enabled) */
5304 anim_info
->iMinAnimate
= 0;
5310 WINE_SPI_WARN(SPI_SETANIMATION
);
5312 case SPI_GETFONTSMOOTHING
:
5313 ret
= get_entry( &entry_FONTSMOOTHING
, val
, ptr
);
5314 if (ret
) *(UINT
*)ptr
= (*(UINT
*)ptr
!= 0);
5316 case SPI_SETFONTSMOOTHING
:
5317 val
= val
? 2 : 0; /* Win NT4/2k/XP behavior */
5318 ret
= set_entry( &entry_FONTSMOOTHING
, val
, ptr
, winini
);
5320 case SPI_SETDRAGWIDTH
:
5321 ret
= set_entry( &entry_DRAGWIDTH
, val
, ptr
, winini
);
5323 case SPI_SETDRAGHEIGHT
:
5324 ret
= set_entry( &entry_DRAGHEIGHT
, val
, ptr
, winini
);
5327 WINE_SPI_FIXME(SPI_SETHANDHELD
);
5328 WINE_SPI_FIXME(SPI_GETLOWPOWERTIMEOUT
);
5329 WINE_SPI_FIXME(SPI_GETPOWEROFFTIMEOUT
);
5330 WINE_SPI_FIXME(SPI_SETLOWPOWERTIMEOUT
);
5331 WINE_SPI_FIXME(SPI_SETPOWEROFFTIMEOUT
);
5333 case SPI_GETLOWPOWERACTIVE
:
5334 ret
= get_entry( &entry_LOWPOWERACTIVE
, val
, ptr
);
5336 case SPI_SETLOWPOWERACTIVE
:
5337 ret
= set_entry( &entry_LOWPOWERACTIVE
, val
, ptr
, winini
);
5339 case SPI_GETPOWEROFFACTIVE
:
5340 ret
= get_entry( &entry_POWEROFFACTIVE
, val
, ptr
);
5342 case SPI_SETPOWEROFFACTIVE
:
5343 ret
= set_entry( &entry_POWEROFFACTIVE
, val
, ptr
, winini
);
5346 WINE_SPI_FIXME(SPI_SETCURSORS
);
5347 WINE_SPI_FIXME(SPI_SETICONS
);
5349 case SPI_GETDEFAULTINPUTLANG
:
5350 ret
= NtUserGetKeyboardLayout(0) != 0;
5353 WINE_SPI_FIXME(SPI_SETDEFAULTINPUTLANG
);
5354 WINE_SPI_FIXME(SPI_SETLANGTOGGLE
);
5356 case SPI_GETWINDOWSEXTENSION
:
5357 WARN( "pretend no support for Win9x Plus! for now.\n" );
5358 ret
= FALSE
; /* yes, this is the result value */
5360 case SPI_SETMOUSETRAILS
:
5361 ret
= set_entry( &entry_MOUSETRAILS
, val
, ptr
, winini
);
5363 case SPI_GETMOUSETRAILS
:
5364 ret
= get_entry( &entry_MOUSETRAILS
, val
, ptr
);
5366 case SPI_GETSNAPTODEFBUTTON
:
5367 ret
= get_entry( &entry_SNAPTODEFBUTTON
, val
, ptr
);
5369 case SPI_SETSNAPTODEFBUTTON
:
5370 ret
= set_entry( &entry_SNAPTODEFBUTTON
, val
, ptr
, winini
);
5372 case SPI_SETSCREENSAVERRUNNING
:
5373 ret
= set_entry( &entry_SCREENSAVERRUNNING
, val
, ptr
, winini
);
5375 case SPI_GETMOUSEHOVERWIDTH
:
5376 ret
= get_entry( &entry_MOUSEHOVERWIDTH
, val
, ptr
);
5378 case SPI_SETMOUSEHOVERWIDTH
:
5379 ret
= set_entry( &entry_MOUSEHOVERWIDTH
, val
, ptr
, winini
);
5381 case SPI_GETMOUSEHOVERHEIGHT
:
5382 ret
= get_entry( &entry_MOUSEHOVERHEIGHT
, val
, ptr
);
5384 case SPI_SETMOUSEHOVERHEIGHT
:
5385 ret
= set_entry( &entry_MOUSEHOVERHEIGHT
, val
, ptr
, winini
);
5387 case SPI_GETMOUSEHOVERTIME
:
5388 ret
= get_entry( &entry_MOUSEHOVERTIME
, val
, ptr
);
5390 case SPI_SETMOUSEHOVERTIME
:
5391 ret
= set_entry( &entry_MOUSEHOVERTIME
, val
, ptr
, winini
);
5393 case SPI_GETWHEELSCROLLLINES
:
5394 ret
= get_entry( &entry_WHEELSCROLLLINES
, val
, ptr
);
5396 case SPI_SETWHEELSCROLLLINES
:
5397 ret
= set_entry( &entry_WHEELSCROLLLINES
, val
, ptr
, winini
);
5399 case SPI_GETMENUSHOWDELAY
:
5400 ret
= get_entry( &entry_MENUSHOWDELAY
, val
, ptr
);
5402 case SPI_SETMENUSHOWDELAY
:
5403 ret
= set_entry( &entry_MENUSHOWDELAY
, val
, ptr
, winini
);
5405 case SPI_GETWHEELSCROLLCHARS
:
5406 ret
= get_entry( &entry_WHEELSCROLLCHARS
, val
, ptr
);
5408 case SPI_SETWHEELSCROLLCHARS
:
5409 ret
= set_entry( &entry_WHEELSCROLLCHARS
, val
, ptr
, winini
);
5412 WINE_SPI_FIXME(SPI_GETSHOWIMEUI
);
5413 WINE_SPI_FIXME(SPI_SETSHOWIMEUI
);
5415 case SPI_GETMOUSESPEED
:
5416 ret
= get_entry( &entry_MOUSESPEED
, val
, ptr
);
5418 case SPI_SETMOUSESPEED
:
5419 ret
= set_entry( &entry_MOUSESPEED
, val
, ptr
, winini
);
5421 case SPI_GETSCREENSAVERRUNNING
:
5422 ret
= get_entry( &entry_SCREENSAVERRUNNING
, val
, ptr
);
5424 case SPI_GETDESKWALLPAPER
:
5425 ret
= get_entry( &entry_DESKWALLPAPER
, val
, ptr
);
5427 case SPI_GETACTIVEWINDOWTRACKING
:
5428 ret
= get_entry( &entry_ACTIVEWINDOWTRACKING
, val
, ptr
);
5430 case SPI_SETACTIVEWINDOWTRACKING
:
5431 ret
= set_entry( &entry_ACTIVEWINDOWTRACKING
, val
, ptr
, winini
);
5433 case SPI_GETMENUANIMATION
:
5434 ret
= get_entry( &entry_MENUANIMATION
, val
, ptr
);
5436 case SPI_SETMENUANIMATION
:
5437 ret
= set_entry( &entry_MENUANIMATION
, val
, ptr
, winini
);
5439 case SPI_GETCOMBOBOXANIMATION
:
5440 ret
= get_entry( &entry_COMBOBOXANIMATION
, val
, ptr
);
5442 case SPI_SETCOMBOBOXANIMATION
:
5443 ret
= set_entry( &entry_COMBOBOXANIMATION
, val
, ptr
, winini
);
5445 case SPI_GETLISTBOXSMOOTHSCROLLING
:
5446 ret
= get_entry( &entry_LISTBOXSMOOTHSCROLLING
, val
, ptr
);
5448 case SPI_SETLISTBOXSMOOTHSCROLLING
:
5449 ret
= set_entry( &entry_LISTBOXSMOOTHSCROLLING
, val
, ptr
, winini
);
5451 case SPI_GETGRADIENTCAPTIONS
:
5452 ret
= get_entry( &entry_GRADIENTCAPTIONS
, val
, ptr
);
5454 case SPI_SETGRADIENTCAPTIONS
:
5455 ret
= set_entry( &entry_GRADIENTCAPTIONS
, val
, ptr
, winini
);
5457 case SPI_GETKEYBOARDCUES
:
5458 ret
= get_entry( &entry_KEYBOARDCUES
, val
, ptr
);
5460 case SPI_SETKEYBOARDCUES
:
5461 ret
= set_entry( &entry_KEYBOARDCUES
, val
, ptr
, winini
);
5463 case SPI_GETACTIVEWNDTRKZORDER
:
5464 ret
= get_entry( &entry_ACTIVEWNDTRKZORDER
, val
, ptr
);
5466 case SPI_SETACTIVEWNDTRKZORDER
:
5467 ret
= set_entry( &entry_ACTIVEWNDTRKZORDER
, val
, ptr
, winini
);
5469 case SPI_GETHOTTRACKING
:
5470 ret
= get_entry( &entry_HOTTRACKING
, val
, ptr
);
5472 case SPI_SETHOTTRACKING
:
5473 ret
= set_entry( &entry_HOTTRACKING
, val
, ptr
, winini
);
5475 case SPI_GETMENUFADE
:
5476 ret
= get_entry( &entry_MENUFADE
, val
, ptr
);
5478 case SPI_SETMENUFADE
:
5479 ret
= set_entry( &entry_MENUFADE
, val
, ptr
, winini
);
5481 case SPI_GETSELECTIONFADE
:
5482 ret
= get_entry( &entry_SELECTIONFADE
, val
, ptr
);
5484 case SPI_SETSELECTIONFADE
:
5485 ret
= set_entry( &entry_SELECTIONFADE
, val
, ptr
, winini
);
5487 case SPI_GETTOOLTIPANIMATION
:
5488 ret
= get_entry( &entry_TOOLTIPANIMATION
, val
, ptr
);
5490 case SPI_SETTOOLTIPANIMATION
:
5491 ret
= set_entry( &entry_TOOLTIPANIMATION
, val
, ptr
, winini
);
5493 case SPI_GETTOOLTIPFADE
:
5494 ret
= get_entry( &entry_TOOLTIPFADE
, val
, ptr
);
5496 case SPI_SETTOOLTIPFADE
:
5497 ret
= set_entry( &entry_TOOLTIPFADE
, val
, ptr
, winini
);
5499 case SPI_GETCURSORSHADOW
:
5500 ret
= get_entry( &entry_CURSORSHADOW
, val
, ptr
);
5502 case SPI_SETCURSORSHADOW
:
5503 ret
= set_entry( &entry_CURSORSHADOW
, val
, ptr
, winini
);
5505 case SPI_GETMOUSESONAR
:
5506 ret
= get_entry( &entry_MOUSESONAR
, val
, ptr
);
5508 case SPI_SETMOUSESONAR
:
5509 ret
= set_entry( &entry_MOUSESONAR
, val
, ptr
, winini
);
5511 case SPI_GETMOUSECLICKLOCK
:
5512 ret
= get_entry( &entry_MOUSECLICKLOCK
, val
, ptr
);
5514 case SPI_SETMOUSECLICKLOCK
:
5515 ret
= set_entry( &entry_MOUSECLICKLOCK
, val
, ptr
, winini
);
5517 case SPI_GETMOUSEVANISH
:
5518 ret
= get_entry( &entry_MOUSEVANISH
, val
, ptr
);
5520 case SPI_SETMOUSEVANISH
:
5521 ret
= set_entry( &entry_MOUSEVANISH
, val
, ptr
, winini
);
5523 case SPI_GETFLATMENU
:
5524 ret
= get_entry( &entry_FLATMENU
, val
, ptr
);
5526 case SPI_SETFLATMENU
:
5527 ret
= set_entry( &entry_FLATMENU
, val
, ptr
, winini
);
5529 case SPI_GETDROPSHADOW
:
5530 ret
= get_entry( &entry_DROPSHADOW
, val
, ptr
);
5532 case SPI_SETDROPSHADOW
:
5533 ret
= set_entry( &entry_DROPSHADOW
, val
, ptr
, winini
);
5535 case SPI_GETBLOCKSENDINPUTRESETS
:
5536 ret
= get_entry( &entry_BLOCKSENDINPUTRESETS
, val
, ptr
);
5538 case SPI_SETBLOCKSENDINPUTRESETS
:
5539 ret
= set_entry( &entry_BLOCKSENDINPUTRESETS
, val
, ptr
, winini
);
5541 case SPI_GETUIEFFECTS
:
5542 ret
= get_entry( &entry_UIEFFECTS
, val
, ptr
);
5544 case SPI_SETUIEFFECTS
:
5545 /* FIXME: this probably should mask other UI effect values when unset */
5546 ret
= set_entry( &entry_UIEFFECTS
, val
, ptr
, winini
);
5548 case SPI_GETDISABLEOVERLAPPEDCONTENT
:
5549 ret
= get_entry( &entry_DISABLEOVERLAPPEDCONTENT
, val
, ptr
);
5551 case SPI_SETDISABLEOVERLAPPEDCONTENT
:
5552 ret
= set_entry( &entry_DISABLEOVERLAPPEDCONTENT
, val
, ptr
, winini
);
5554 case SPI_GETCLIENTAREAANIMATION
:
5555 ret
= get_entry( &entry_CLIENTAREAANIMATION
, val
, ptr
);
5557 case SPI_SETCLIENTAREAANIMATION
:
5558 ret
= set_entry( &entry_CLIENTAREAANIMATION
, val
, ptr
, winini
);
5560 case SPI_GETCLEARTYPE
:
5561 ret
= get_entry( &entry_CLEARTYPE
, val
, ptr
);
5563 case SPI_SETCLEARTYPE
:
5564 ret
= set_entry( &entry_CLEARTYPE
, val
, ptr
, winini
);
5566 case SPI_GETSPEECHRECOGNITION
:
5567 ret
= get_entry( &entry_SPEECHRECOGNITION
, val
, ptr
);
5569 case SPI_SETSPEECHRECOGNITION
:
5570 ret
= set_entry( &entry_SPEECHRECOGNITION
, val
, ptr
, winini
);
5572 case SPI_GETFOREGROUNDLOCKTIMEOUT
:
5573 ret
= get_entry( &entry_FOREGROUNDLOCKTIMEOUT
, val
, ptr
);
5575 case SPI_SETFOREGROUNDLOCKTIMEOUT
:
5576 /* FIXME: this should check that the calling thread
5577 * is able to change the foreground window */
5578 ret
= set_entry( &entry_FOREGROUNDLOCKTIMEOUT
, val
, ptr
, winini
);
5580 case SPI_GETACTIVEWNDTRKTIMEOUT
:
5581 ret
= get_entry( &entry_ACTIVEWNDTRKTIMEOUT
, val
, ptr
);
5583 case SPI_SETACTIVEWNDTRKTIMEOUT
:
5584 ret
= get_entry( &entry_ACTIVEWNDTRKTIMEOUT
, val
, ptr
);
5586 case SPI_GETFOREGROUNDFLASHCOUNT
:
5587 ret
= get_entry( &entry_FOREGROUNDFLASHCOUNT
, val
, ptr
);
5589 case SPI_SETFOREGROUNDFLASHCOUNT
:
5590 ret
= set_entry( &entry_FOREGROUNDFLASHCOUNT
, val
, ptr
, winini
);
5592 case SPI_GETCARETWIDTH
:
5593 ret
= get_entry( &entry_CARETWIDTH
, val
, ptr
);
5595 case SPI_SETCARETWIDTH
:
5596 ret
= set_entry( &entry_CARETWIDTH
, val
, ptr
, winini
);
5598 case SPI_GETMOUSECLICKLOCKTIME
:
5599 ret
= get_entry( &entry_MOUSECLICKLOCKTIME
, val
, ptr
);
5601 case SPI_SETMOUSECLICKLOCKTIME
:
5602 ret
= set_entry( &entry_MOUSECLICKLOCKTIME
, val
, ptr
, winini
);
5604 case SPI_GETFONTSMOOTHINGTYPE
:
5605 ret
= get_entry( &entry_FONTSMOOTHINGTYPE
, val
, ptr
);
5607 case SPI_SETFONTSMOOTHINGTYPE
:
5608 ret
= set_entry( &entry_FONTSMOOTHINGTYPE
, val
, ptr
, winini
);
5610 case SPI_GETFONTSMOOTHINGCONTRAST
:
5611 ret
= get_entry( &entry_FONTSMOOTHINGCONTRAST
, val
, ptr
);
5613 case SPI_SETFONTSMOOTHINGCONTRAST
:
5614 ret
= set_entry( &entry_FONTSMOOTHINGCONTRAST
, val
, ptr
, winini
);
5616 case SPI_GETFOCUSBORDERWIDTH
:
5617 ret
= get_entry( &entry_FOCUSBORDERWIDTH
, val
, ptr
);
5619 case SPI_GETFOCUSBORDERHEIGHT
:
5620 ret
= get_entry( &entry_FOCUSBORDERHEIGHT
, val
, ptr
);
5622 case SPI_SETFOCUSBORDERWIDTH
:
5623 ret
= set_entry( &entry_FOCUSBORDERWIDTH
, val
, ptr
, winini
);
5625 case SPI_SETFOCUSBORDERHEIGHT
:
5626 ret
= set_entry( &entry_FOCUSBORDERHEIGHT
, val
, ptr
, winini
);
5628 case SPI_GETFONTSMOOTHINGORIENTATION
:
5629 ret
= get_entry( &entry_FONTSMOOTHINGORIENTATION
, val
, ptr
);
5631 case SPI_SETFONTSMOOTHINGORIENTATION
:
5632 ret
= set_entry( &entry_FONTSMOOTHINGORIENTATION
, val
, ptr
, winini
);
5634 case SPI_GETAUDIODESCRIPTION
:
5636 AUDIODESCRIPTION
*audio
= ptr
;
5637 if (audio
&& audio
->cbSize
== sizeof(AUDIODESCRIPTION
) && val
== sizeof(AUDIODESCRIPTION
) )
5639 ret
= get_entry( &entry_AUDIODESC_ON
, 0, &audio
->Enabled
) &&
5640 get_entry( &entry_AUDIODESC_LOCALE
, 0, &audio
->Locale
);
5644 case SPI_SETAUDIODESCRIPTION
:
5646 AUDIODESCRIPTION
*audio
= ptr
;
5647 if (audio
&& audio
->cbSize
== sizeof(AUDIODESCRIPTION
) && val
== sizeof(AUDIODESCRIPTION
) )
5649 ret
= set_entry( &entry_AUDIODESC_ON
, 0, &audio
->Enabled
, winini
) &&
5650 set_entry( &entry_AUDIODESC_LOCALE
, 0, &audio
->Locale
, winini
);
5655 FIXME( "Unknown action: %u\n", action
);
5656 RtlSetLastWin32Error( ERROR_INVALID_SPI_VALUE
);
5661 if (ret
&& (winini
& SPIF_UPDATEINIFILE
))
5663 static const WCHAR emptyW
[1];
5664 if (winini
& (SPIF_SENDWININICHANGE
| SPIF_SENDCHANGE
))
5665 send_message_timeout( HWND_BROADCAST
, WM_SETTINGCHANGE
, action
, (LPARAM
) emptyW
,
5666 SMTO_ABORTIFHUNG
, 2000, FALSE
);
5668 TRACE( "(%u, %u, %p, %u) ret %d\n", action
, val
, ptr
, winini
, ret
);
5671 #undef WINE_SPI_FIXME
5672 #undef WINE_SPI_WARN
5675 int get_system_metrics( int index
)
5677 NONCLIENTMETRICSW ncm
;
5678 MINIMIZEDMETRICS mm
;
5684 /* some metrics are dynamic */
5689 get_entry( &entry_SCROLLWIDTH
, 0, &ret
);
5690 return max( ret
, 8 );
5692 ncm
.cbSize
= sizeof(ncm
);
5693 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5694 return ncm
.iCaptionHeight
+ 1;
5697 /* SM_C{X,Y}BORDER always returns 1 regardless of 'BorderWidth' value in registry */
5706 get_entry( &entry_SCROLLHEIGHT
, 0, &ret
);
5707 return max( ret
, 8 );
5710 return map_to_dpi( 32, get_system_dpi() );
5713 ret
= map_to_dpi( 32, get_system_dpi() );
5714 if (ret
>= 64) return 64;
5715 if (ret
>= 48) return 48;
5718 ncm
.cbSize
= sizeof(ncm
);
5719 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5720 return ncm
.iMenuHeight
+ 1;
5721 case SM_CXFULLSCREEN
:
5722 /* see the remark for SM_CXMAXIMIZED, at least this formulation is correct */
5723 return get_system_metrics( SM_CXMAXIMIZED
) - 2 * get_system_metrics( SM_CXFRAME
);
5724 case SM_CYFULLSCREEN
:
5725 /* see the remark for SM_CYMAXIMIZED, at least this formulation is
5727 return get_system_metrics( SM_CYMAXIMIZED
) - get_system_metrics( SM_CYMIN
);
5728 case SM_CYKANJIWINDOW
:
5730 case SM_MOUSEPRESENT
:
5735 get_entry( &entry_MOUSEBUTTONSWAP
, 0, &ret
);
5743 ncm
.cbSize
= sizeof(ncm
);
5744 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5745 hdc
= get_display_dc();
5746 get_text_metr_size( hdc
, &ncm
.lfCaptionFont
, NULL
, &ret
);
5747 release_display_dc( hdc
);
5748 return 3 * ncm
.iCaptionWidth
+ ncm
.iCaptionHeight
+ 4 * ret
+
5749 2 * get_system_metrics( SM_CXFRAME
) + 4;
5751 return get_system_metrics( SM_CYCAPTION
) + 2 * get_system_metrics( SM_CYFRAME
);
5753 get_entry( &entry_CAPTIONWIDTH
, 0, &ret
);
5754 return max( ret
, 8 );
5756 ncm
.cbSize
= sizeof(ncm
);
5757 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5758 return ncm
.iCaptionHeight
;
5760 get_entry( &entry_BORDER
, 0, &ret
);
5761 ret
= max( ret
, 1 );
5762 return get_system_metrics( SM_CXDLGFRAME
) + ret
;
5764 get_entry( &entry_BORDER
, 0, &ret
);
5765 ret
= max( ret
, 1 );
5766 return get_system_metrics( SM_CYDLGFRAME
) + ret
;
5768 return get_system_metrics( SM_CXMIN
);
5770 return get_system_metrics( SM_CYMIN
);
5771 case SM_CXDOUBLECLK
:
5772 get_entry( &entry_DOUBLECLKWIDTH
, 0, &ret
);
5774 case SM_CYDOUBLECLK
:
5775 get_entry( &entry_DOUBLECLKHEIGHT
, 0, &ret
);
5777 case SM_CXICONSPACING
:
5778 im
.cbSize
= sizeof(im
);
5779 NtUserSystemParametersInfo( SPI_GETICONMETRICS
, sizeof(im
), &im
, 0 );
5780 return im
.iHorzSpacing
;
5781 case SM_CYICONSPACING
:
5782 im
.cbSize
= sizeof(im
);
5783 NtUserSystemParametersInfo( SPI_GETICONMETRICS
, sizeof(im
), &im
, 0 );
5784 return im
.iVertSpacing
;
5785 case SM_MENUDROPALIGNMENT
:
5786 NtUserSystemParametersInfo( SPI_GETMENUDROPALIGNMENT
, 0, &ret
, 0 );
5790 case SM_DBCSENABLED
:
5791 return ansi_cp
.MaximumCharacterSize
> 1;
5792 case SM_CMOUSEBUTTONS
:
5797 return get_system_metrics( SM_CXBORDER
) + 1;
5799 return get_system_metrics( SM_CYBORDER
) + 1;
5800 case SM_CXMINSPACING
:
5801 mm
.cbSize
= sizeof(mm
);
5802 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(mm
), &mm
, 0 );
5803 return get_system_metrics( SM_CXMINIMIZED
) + mm
.iHorzGap
;
5804 case SM_CYMINSPACING
:
5805 mm
.cbSize
= sizeof(mm
);
5806 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(mm
), &mm
, 0 );
5807 return get_system_metrics( SM_CYMINIMIZED
) + mm
.iVertGap
;
5810 return map_to_dpi( 16, get_system_dpi() ) & ~1;
5811 case SM_CYSMCAPTION
:
5812 ncm
.cbSize
= sizeof(ncm
);
5813 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5814 return ncm
.iSmCaptionHeight
+ 1;
5816 get_entry( &entry_SMCAPTIONWIDTH
, 0, &ret
);
5819 ncm
.cbSize
= sizeof(ncm
);
5820 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5821 return ncm
.iSmCaptionHeight
;
5823 get_entry( &entry_MENUWIDTH
, 0, &ret
);
5826 ncm
.cbSize
= sizeof(ncm
);
5827 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5828 return ncm
.iMenuHeight
;
5830 mm
.cbSize
= sizeof(mm
);
5831 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(mm
), &mm
, 0 );
5833 case SM_CXMINIMIZED
:
5834 mm
.cbSize
= sizeof(mm
);
5835 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(mm
), &mm
, 0 );
5836 return mm
.iWidth
+ 6;
5837 case SM_CYMINIMIZED
:
5838 ncm
.cbSize
= sizeof(ncm
);
5839 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5840 return ncm
.iCaptionHeight
+ 6;
5842 return get_system_metrics( SM_CXVIRTUALSCREEN
) + 4 + 2 * get_system_metrics( SM_CXFRAME
);
5844 return get_system_metrics( SM_CYVIRTUALSCREEN
) + 4 + 2 * get_system_metrics( SM_CYFRAME
);
5845 case SM_CXMAXIMIZED
:
5846 /* FIXME: subtract the width of any vertical application toolbars*/
5847 return get_system_metrics( SM_CXSCREEN
) + 2 * get_system_metrics( SM_CXFRAME
);
5848 case SM_CYMAXIMIZED
:
5849 /* FIXME: subtract the width of any horizontal application toolbars*/
5850 return get_system_metrics( SM_CYSCREEN
) + 2 * get_system_metrics( SM_CYCAPTION
);
5852 return 3; /* FIXME */
5854 return 0; /* 0 = ok, 1 = failsafe, 2 = failsafe + network */
5856 get_entry( &entry_DRAGWIDTH
, 0, &ret
);
5859 get_entry( &entry_DRAGHEIGHT
, 0, &ret
);
5862 get_entry( &entry_SHOWSOUNDS
, 0, &ret
);
5864 case SM_CXMENUCHECK
:
5865 case SM_CYMENUCHECK
:
5868 ncm
.cbSize
= sizeof(ncm
);
5869 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5870 hdc
= get_display_dc();
5871 get_text_metr_size( hdc
, &ncm
.lfMenuFont
, &tm
, NULL
);
5872 release_display_dc( hdc
);
5873 return tm
.tmHeight
<= 0 ? 13 : ((tm
.tmHeight
+ tm
.tmExternalLeading
+ 1) / 2) * 2 - 1;
5875 case SM_SLOWMACHINE
:
5876 return 0; /* Never true */
5877 case SM_MIDEASTENABLED
:
5878 return 0; /* FIXME */
5879 case SM_MOUSEWHEELPRESENT
:
5882 rect
= get_primary_monitor_rect( get_thread_dpi() );
5883 return rect
.right
- rect
.left
;
5885 rect
= get_primary_monitor_rect( get_thread_dpi() );
5886 return rect
.bottom
- rect
.top
;
5887 case SM_XVIRTUALSCREEN
:
5888 rect
= get_virtual_screen_rect( get_thread_dpi() );
5890 case SM_YVIRTUALSCREEN
:
5891 rect
= get_virtual_screen_rect( get_thread_dpi() );
5893 case SM_CXVIRTUALSCREEN
:
5894 rect
= get_virtual_screen_rect( get_thread_dpi() );
5895 return rect
.right
- rect
.left
;
5896 case SM_CYVIRTUALSCREEN
:
5897 rect
= get_virtual_screen_rect( get_thread_dpi() );
5898 return rect
.bottom
- rect
.top
;
5900 if (!lock_display_devices()) return FALSE
;
5901 ret
= active_monitor_count();
5902 unlock_display_devices();
5904 case SM_SAMEDISPLAYFORMAT
:
5907 return 0; /* FIXME */
5908 case SM_CXFOCUSBORDER
:
5909 case SM_CYFOCUSBORDER
:
5912 case SM_MEDIACENTER
:
5921 static int get_system_metrics_for_dpi( int index
, unsigned int dpi
)
5923 NONCLIENTMETRICSW ncm
;
5928 /* some metrics are dynamic */
5933 get_entry_dpi( &entry_SCROLLWIDTH
, 0, &ret
, dpi
);
5934 return max( ret
, 8 );
5936 ncm
.cbSize
= sizeof(ncm
);
5937 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5938 return ncm
.iCaptionHeight
+ 1;
5943 get_entry_dpi( &entry_SCROLLHEIGHT
, 0, &ret
, dpi
);
5944 return max( ret
, 8 );
5947 return map_to_dpi( 32, dpi
);
5950 ret
= map_to_dpi( 32, dpi
);
5951 if (ret
>= 64) return 64;
5952 if (ret
>= 48) return 48;
5955 ncm
.cbSize
= sizeof(ncm
);
5956 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5957 return ncm
.iMenuHeight
+ 1;
5959 get_entry_dpi( &entry_CAPTIONWIDTH
, 0, &ret
, dpi
);
5960 return max( ret
, 8 );
5962 ncm
.cbSize
= sizeof(ncm
);
5963 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5964 return ncm
.iCaptionHeight
;
5966 get_entry_dpi( &entry_BORDER
, 0, &ret
, dpi
);
5967 ret
= max( ret
, 1 );
5968 return get_system_metrics_for_dpi( SM_CXDLGFRAME
, dpi
) + ret
;
5970 get_entry_dpi( &entry_BORDER
, 0, &ret
, dpi
);
5971 ret
= max( ret
, 1 );
5972 return get_system_metrics_for_dpi( SM_CYDLGFRAME
, dpi
) + ret
;
5973 case SM_CXICONSPACING
:
5974 im
.cbSize
= sizeof(im
);
5975 NtUserSystemParametersInfoForDpi( SPI_GETICONMETRICS
, sizeof(im
), &im
, 0, dpi
);
5976 return im
.iHorzSpacing
;
5977 case SM_CYICONSPACING
:
5978 im
.cbSize
= sizeof(im
);
5979 NtUserSystemParametersInfoForDpi( SPI_GETICONMETRICS
, sizeof(im
), &im
, 0, dpi
);
5980 return im
.iVertSpacing
;
5983 return map_to_dpi( 16, dpi
) & ~1;
5984 case SM_CYSMCAPTION
:
5985 ncm
.cbSize
= sizeof(ncm
);
5986 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5987 return ncm
.iSmCaptionHeight
+ 1;
5989 get_entry_dpi( &entry_SMCAPTIONWIDTH
, 0, &ret
, dpi
);
5992 ncm
.cbSize
= sizeof(ncm
);
5993 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5994 return ncm
.iSmCaptionHeight
;
5996 get_entry_dpi( &entry_MENUWIDTH
, 0, &ret
, dpi
);
5999 ncm
.cbSize
= sizeof(ncm
);
6000 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
6001 return ncm
.iMenuHeight
;
6002 case SM_CXMENUCHECK
:
6003 case SM_CYMENUCHECK
:
6006 ncm
.cbSize
= sizeof(ncm
);
6007 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
6008 hdc
= get_display_dc();
6009 get_text_metr_size( hdc
, &ncm
.lfMenuFont
, &tm
, NULL
);
6010 release_display_dc( hdc
);
6011 return tm
.tmHeight
<= 0 ? 13 : ((tm
.tmHeight
+ tm
.tmExternalLeading
- 1) | 1);
6014 return get_system_metrics( index
);
6018 COLORREF
get_sys_color( int index
)
6022 if (index
>= 0 && index
< ARRAY_SIZE( system_colors
))
6023 get_entry( &system_colors
[index
], 0, &ret
);
6027 HBRUSH
get_55aa_brush(void)
6029 static const WORD pattern
[] = { 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa };
6030 static HBRUSH brush_55aa
;
6034 HBITMAP bitmap
= NtGdiCreateBitmap( 8, 8, 1, 1, pattern
);
6035 HBRUSH brush
= NtGdiCreatePatternBrushInternal( bitmap
, FALSE
, FALSE
);
6036 NtGdiDeleteObjectApp( bitmap
);
6037 make_gdi_object_system( brush
, TRUE
);
6038 if (InterlockedCompareExchangePointer( (void **)&brush_55aa
, brush
, 0 ))
6040 make_gdi_object_system( brush
, FALSE
);
6041 NtGdiDeleteObjectApp( brush
);
6047 HBRUSH
get_sys_color_brush( unsigned int index
)
6049 if (index
== COLOR_55AA_BRUSH
) return get_55aa_brush();
6050 if (index
>= ARRAY_SIZE( system_colors
)) return 0;
6052 if (!system_colors
[index
].brush
)
6054 HBRUSH brush
= NtGdiCreateSolidBrush( get_sys_color( index
), NULL
);
6055 make_gdi_object_system( brush
, TRUE
);
6056 if (InterlockedCompareExchangePointer( (void **)&system_colors
[index
].brush
, brush
, 0 ))
6058 make_gdi_object_system( brush
, FALSE
);
6059 NtGdiDeleteObjectApp( brush
);
6062 return system_colors
[index
].brush
;
6065 HPEN
get_sys_color_pen( unsigned int index
)
6067 if (index
>= ARRAY_SIZE( system_colors
)) return 0;
6069 if (!system_colors
[index
].pen
)
6071 HPEN pen
= NtGdiCreatePen( PS_SOLID
, 1, get_sys_color( index
), NULL
);
6072 make_gdi_object_system( pen
, TRUE
);
6073 if (InterlockedCompareExchangePointer( (void **)&system_colors
[index
].pen
, pen
, 0 ))
6075 make_gdi_object_system( pen
, FALSE
);
6076 NtGdiDeleteObjectApp( pen
);
6079 return system_colors
[index
].pen
;
6082 /**********************************************************************
6083 * NtUserGetDoubleClickTime (win32u.@)
6085 UINT WINAPI
NtUserGetDoubleClickTime(void)
6089 get_entry( &entry_DOUBLECLICKTIME
, 0, &time
);
6090 if (!time
) time
= 500;
6094 /*************************************************************************
6095 * NtUserSetSysColors (win32u.@)
6097 BOOL WINAPI
NtUserSetSysColors( INT count
, const INT
*colors
, const COLORREF
*values
)
6101 if (IS_INTRESOURCE(colors
)) return FALSE
; /* stupid app passes a color instead of an array */
6103 for (i
= 0; i
< count
; i
++)
6104 if (colors
[i
] >= 0 && colors
[i
] <= ARRAY_SIZE( system_colors
))
6105 set_entry( &system_colors
[colors
[i
]], values
[i
], 0, 0 );
6107 /* Send WM_SYSCOLORCHANGE message to all windows */
6108 send_message_timeout( HWND_BROADCAST
, WM_SYSCOLORCHANGE
, 0, 0,
6109 SMTO_ABORTIFHUNG
, 2000, FALSE
);
6110 /* Repaint affected portions of all visible windows */
6111 NtUserRedrawWindow( 0, NULL
, 0, RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_ALLCHILDREN
);
6116 static LONG dpi_awareness
;
6118 /***********************************************************************
6119 * NtUserSetProcessDpiAwarenessContext (win32u.@)
6121 BOOL WINAPI
NtUserSetProcessDpiAwarenessContext( ULONG awareness
, ULONG unknown
)
6125 case NTUSER_DPI_UNAWARE
:
6126 case NTUSER_DPI_SYSTEM_AWARE
:
6127 case NTUSER_DPI_PER_MONITOR_AWARE
:
6128 case NTUSER_DPI_PER_MONITOR_AWARE_V2
:
6129 case NTUSER_DPI_PER_UNAWARE_GDISCALED
:
6132 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
6136 return !InterlockedCompareExchange( &dpi_awareness
, awareness
, 0 );
6139 /***********************************************************************
6140 * NtUserGetProcessDpiAwarenessContext (win32u.@)
6142 ULONG WINAPI
NtUserGetProcessDpiAwarenessContext( HANDLE process
)
6146 if (process
&& process
!= GetCurrentProcess())
6148 WARN( "not supported on other process %p\n", process
);
6149 return NTUSER_DPI_UNAWARE
;
6152 val
= ReadNoFence( &dpi_awareness
);
6153 if (!val
) return NTUSER_DPI_UNAWARE
;
6157 BOOL
message_beep( UINT i
)
6160 NtUserSystemParametersInfo( SPI_GETBEEP
, 0, &active
, FALSE
);
6161 if (active
) user_driver
->pBeep();
6165 static DWORD exiting_thread_id
;
6167 /**********************************************************************
6170 BOOL
is_exiting_thread( DWORD tid
)
6172 return tid
== exiting_thread_id
;
6175 static void thread_detach(void)
6177 struct user_thread_info
*thread_info
= get_user_thread_info();
6179 user_driver
->pThreadDetach();
6181 free( thread_info
->key_state
);
6182 thread_info
->key_state
= 0;
6183 free( thread_info
->rawinput
);
6185 destroy_thread_windows();
6186 cleanup_imm_thread();
6187 NtClose( thread_info
->server_queue
);
6189 exiting_thread_id
= 0;
6192 /***********************************************************************
6193 * NtUserCallNoParam (win32u.@)
6195 ULONG_PTR WINAPI
NtUserCallNoParam( ULONG code
)
6199 case NtUserCallNoParam_DestroyCaret
:
6200 return destroy_caret();
6202 case NtUserCallNoParam_GetDesktopWindow
:
6203 return HandleToUlong( get_desktop_window() );
6205 case NtUserCallNoParam_GetDialogBaseUnits
:
6206 return get_dialog_base_units();
6208 case NtUserCallNoParam_GetInputState
:
6209 return get_input_state();
6211 case NtUserCallNoParam_GetProcessDefaultLayout
:
6212 return process_layout
;
6214 case NtUserCallNoParam_GetProgmanWindow
:
6215 return HandleToUlong( get_progman_window() );
6217 case NtUserCallNoParam_GetShellWindow
:
6218 return HandleToUlong( get_shell_window() );
6220 case NtUserCallNoParam_GetTaskmanWindow
:
6221 return HandleToUlong( get_taskman_window() );
6223 case NtUserCallNoParam_ReleaseCapture
:
6224 return release_capture();
6226 /* temporary exports */
6227 case NtUserExitingThread
:
6228 exiting_thread_id
= GetCurrentThreadId();
6231 case NtUserThreadDetach
:
6236 FIXME( "invalid code %u\n", (int)code
);
6241 /***********************************************************************
6242 * NtUserCallOneParam (win32u.@)
6244 ULONG_PTR WINAPI
NtUserCallOneParam( ULONG_PTR arg
, ULONG code
)
6248 case NtUserCallOneParam_BeginDeferWindowPos
:
6249 return HandleToUlong( begin_defer_window_pos( arg
));
6251 case NtUserCallOneParam_CreateCursorIcon
:
6252 return HandleToUlong( alloc_cursoricon_handle( arg
));
6254 case NtUserCallOneParam_CreateMenu
:
6255 return HandleToUlong( create_menu( arg
) );
6257 case NtUserCallOneParam_EnableDC
:
6258 return set_dce_flags( UlongToHandle(arg
), DCHF_ENABLEDC
);
6260 case NtUserCallOneParam_EnableThunkLock
:
6261 enable_thunk_lock
= arg
;
6264 case NtUserCallOneParam_EnumClipboardFormats
:
6265 return enum_clipboard_formats( arg
);
6267 case NtUserCallOneParam_GetClipCursor
:
6268 return get_clip_cursor( (RECT
*)arg
);
6270 case NtUserCallOneParam_GetCursorPos
:
6271 return get_cursor_pos( (POINT
*)arg
);
6273 case NtUserCallOneParam_GetIconParam
:
6274 return get_icon_param( UlongToHandle(arg
) );
6276 case NtUserCallOneParam_GetMenuItemCount
:
6277 return get_menu_item_count( UlongToHandle(arg
) );
6279 case NtUserCallOneParam_GetSysColor
:
6280 return get_sys_color( arg
);
6282 case NtUserCallOneParam_IsWindowRectFullScreen
:
6283 return is_window_rect_full_screen( (const RECT
*)arg
);
6285 case NtUserCallOneParam_RealizePalette
:
6286 return realize_palette( UlongToHandle(arg
) );
6288 case NtUserCallOneParam_GetPrimaryMonitorRect
:
6289 *(RECT
*)arg
= get_primary_monitor_rect( 0 );
6292 case NtUserCallOneParam_GetSysColorBrush
:
6293 return HandleToUlong( get_sys_color_brush(arg
) );
6295 case NtUserCallOneParam_GetSysColorPen
:
6296 return HandleToUlong( get_sys_color_pen(arg
) );
6298 case NtUserCallOneParam_GetSystemMetrics
:
6299 return get_system_metrics( arg
);
6301 case NtUserCallOneParam_GetVirtualScreenRect
:
6302 *(RECT
*)arg
= get_virtual_screen_rect( 0 );
6305 case NtUserCallOneParam_MessageBeep
:
6306 return message_beep( arg
);
6308 case NtUserCallOneParam_ReplyMessage
:
6309 return reply_message_result( arg
);
6311 case NtUserCallOneParam_SetCaretBlinkTime
:
6312 return set_caret_blink_time( arg
);
6314 case NtUserCallOneParam_SetProcessDefaultLayout
:
6315 process_layout
= arg
;
6318 /* temporary exports */
6319 case NtUserGetDeskPattern
:
6320 return get_entry( &entry_DESKPATTERN
, 256, (WCHAR
*)arg
);
6323 FIXME( "invalid code %u\n", (int)code
);
6328 /***********************************************************************
6329 * NtUserCallTwoParam (win32u.@)
6331 ULONG_PTR WINAPI
NtUserCallTwoParam( ULONG_PTR arg1
, ULONG_PTR arg2
, ULONG code
)
6335 case NtUserCallTwoParam_GetDialogProc
:
6336 return (ULONG_PTR
)get_dialog_proc( (DLGPROC
)arg1
, arg2
);
6338 case NtUserCallTwoParam_GetMenuInfo
:
6339 return get_menu_info( UlongToHandle(arg1
), (MENUINFO
*)arg2
);
6341 case NtUserCallTwoParam_GetMonitorInfo
:
6342 return get_monitor_info( UlongToHandle(arg1
), (MONITORINFO
*)arg2
);
6344 case NtUserCallTwoParam_GetSystemMetricsForDpi
:
6345 return get_system_metrics_for_dpi( arg1
, arg2
);
6347 case NtUserCallTwoParam_MonitorFromRect
:
6348 return HandleToUlong( monitor_from_rect( (const RECT
*)arg1
, arg2
, get_thread_dpi() ));
6350 case NtUserCallTwoParam_SetCaretPos
:
6351 return set_caret_pos( arg1
, arg2
);
6353 case NtUserCallTwoParam_SetIconParam
:
6354 return set_icon_param( UlongToHandle(arg1
), arg2
);
6356 case NtUserCallTwoParam_UnhookWindowsHook
:
6357 return unhook_windows_hook( arg1
, (HOOKPROC
)arg2
);
6359 /* temporary exports */
6360 case NtUserAllocWinProc
:
6361 return (UINT_PTR
)alloc_winproc( (WNDPROC
)arg1
, arg2
);
6364 FIXME( "invalid code %u\n", (int)code
);
6369 /***********************************************************************
6370 * NtUserDisplayConfigGetDeviceInfo (win32u.@)
6372 NTSTATUS WINAPI
NtUserDisplayConfigGetDeviceInfo( DISPLAYCONFIG_DEVICE_INFO_HEADER
*packet
)
6374 NTSTATUS ret
= STATUS_UNSUCCESSFUL
;
6376 TRACE( "packet %p.\n", packet
);
6378 if (!packet
|| packet
->size
< sizeof(*packet
))
6379 return STATUS_UNSUCCESSFUL
;
6381 switch (packet
->type
)
6383 case DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME
:
6385 DISPLAYCONFIG_SOURCE_DEVICE_NAME
*source_name
= (DISPLAYCONFIG_SOURCE_DEVICE_NAME
*)packet
;
6386 struct adapter
*adapter
;
6388 TRACE( "DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME.\n" );
6390 if (packet
->size
< sizeof(*source_name
))
6391 return STATUS_INVALID_PARAMETER
;
6393 if (!lock_display_devices()) return STATUS_UNSUCCESSFUL
;
6395 LIST_FOR_EACH_ENTRY(adapter
, &adapters
, struct adapter
, entry
)
6397 if (source_name
->header
.id
!= adapter
->id
) continue;
6398 if (memcmp( &source_name
->header
.adapterId
, &adapter
->gpu_luid
, sizeof(adapter
->gpu_luid
) )) continue;
6400 lstrcpyW( source_name
->viewGdiDeviceName
, adapter
->dev
.device_name
);
6401 ret
= STATUS_SUCCESS
;
6405 unlock_display_devices();
6408 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME
:
6410 DISPLAYCONFIG_TARGET_DEVICE_NAME
*target_name
= (DISPLAYCONFIG_TARGET_DEVICE_NAME
*)packet
;
6411 char buffer
[ARRAY_SIZE(target_name
->monitorFriendlyDeviceName
)];
6412 struct monitor
*monitor
;
6414 TRACE( "DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME.\n" );
6416 if (packet
->size
< sizeof(*target_name
))
6417 return STATUS_INVALID_PARAMETER
;
6419 if (!lock_display_devices()) return STATUS_UNSUCCESSFUL
;
6421 memset( &target_name
->flags
, 0, sizeof(*target_name
) - offsetof(DISPLAYCONFIG_TARGET_DEVICE_NAME
, flags
) );
6423 LIST_FOR_EACH_ENTRY(monitor
, &monitors
, struct monitor
, entry
)
6425 if (target_name
->header
.id
!= monitor
->output_id
) continue;
6426 if (memcmp( &target_name
->header
.adapterId
, &monitor
->adapter
->gpu_luid
,
6427 sizeof(monitor
->adapter
->gpu_luid
) ))
6430 target_name
->outputTechnology
= DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL
;
6431 snprintf( buffer
, ARRAY_SIZE(buffer
), "Display%u", monitor
->output_id
+ 1 );
6432 asciiz_to_unicode( target_name
->monitorFriendlyDeviceName
, buffer
);
6433 lstrcpyW( target_name
->monitorDevicePath
, monitor
->dev
.interface_name
);
6434 if (monitor
->edid_info
.flags
& MONITOR_INFO_HAS_MONITOR_ID
)
6436 target_name
->edidManufactureId
= monitor
->edid_info
.manufacturer
;
6437 target_name
->edidProductCodeId
= monitor
->edid_info
.product_code
;
6438 target_name
->flags
.edidIdsValid
= 1;
6440 if (monitor
->edid_info
.flags
& MONITOR_INFO_HAS_MONITOR_NAME
)
6442 wcscpy( target_name
->monitorFriendlyDeviceName
, monitor
->edid_info
.monitor_name
);
6443 target_name
->flags
.friendlyNameFromEdid
= 1;
6445 ret
= STATUS_SUCCESS
;
6449 unlock_display_devices();
6452 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE
:
6454 DISPLAYCONFIG_TARGET_PREFERRED_MODE
*preferred_mode
= (DISPLAYCONFIG_TARGET_PREFERRED_MODE
*)packet
;
6455 DISPLAYCONFIG_VIDEO_SIGNAL_INFO
*signal_info
= &preferred_mode
->targetMode
.targetVideoSignalInfo
;
6456 unsigned int i
, display_freq
;
6457 DEVMODEW
*found_mode
= NULL
;
6458 BOOL have_edid_mode
= FALSE
;
6459 struct monitor
*monitor
;
6461 FIXME( "DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE semi-stub.\n" );
6463 if (packet
->size
< sizeof(*preferred_mode
))
6464 return STATUS_INVALID_PARAMETER
;
6466 if (!lock_display_devices()) return STATUS_UNSUCCESSFUL
;
6468 memset( &preferred_mode
->width
, 0, sizeof(*preferred_mode
) - offsetof(DISPLAYCONFIG_TARGET_PREFERRED_MODE
, width
) );
6470 LIST_FOR_EACH_ENTRY(monitor
, &monitors
, struct monitor
, entry
)
6472 if (preferred_mode
->header
.id
!= monitor
->output_id
) continue;
6473 if (memcmp( &preferred_mode
->header
.adapterId
, &monitor
->adapter
->gpu_luid
,
6474 sizeof(monitor
->adapter
->gpu_luid
) ))
6477 for (i
= 0; i
< monitor
->adapter
->mode_count
; ++i
)
6479 DEVMODEW
*mode
= &monitor
->adapter
->modes
[i
];
6481 if (!have_edid_mode
&& monitor
->edid_info
.flags
& MONITOR_INFO_HAS_PREFERRED_MODE
6482 && mode
->dmPelsWidth
== monitor
->edid_info
.preferred_width
6483 && mode
->dmPelsHeight
== monitor
->edid_info
.preferred_height
)
6486 have_edid_mode
= TRUE
;
6489 if (!have_edid_mode
&& (!found_mode
6490 || (mode
->dmPelsWidth
> found_mode
->dmPelsWidth
&& mode
->dmPelsHeight
>= found_mode
->dmPelsHeight
)
6491 || (mode
->dmPelsHeight
> found_mode
->dmPelsHeight
&& mode
->dmPelsWidth
>= found_mode
->dmPelsWidth
)))
6494 if (mode
->dmPelsWidth
== found_mode
->dmPelsWidth
6495 && mode
->dmPelsHeight
== found_mode
->dmPelsHeight
6496 && mode
->dmDisplayFrequency
> found_mode
->dmDisplayFrequency
)
6502 ERR( "No mode found.\n" );
6505 preferred_mode
->width
= found_mode
->dmPelsWidth
;
6506 preferred_mode
->height
= found_mode
->dmPelsHeight
;
6507 display_freq
= found_mode
->dmDisplayFrequency
;
6509 signal_info
->pixelRate
= display_freq
* preferred_mode
->width
* preferred_mode
->height
;
6510 signal_info
->hSyncFreq
.Numerator
= display_freq
* preferred_mode
->width
;
6511 signal_info
->hSyncFreq
.Denominator
= 1;
6512 signal_info
->vSyncFreq
.Numerator
= display_freq
;
6513 signal_info
->vSyncFreq
.Denominator
= 1;
6514 signal_info
->activeSize
.cx
= preferred_mode
->width
;
6515 signal_info
->activeSize
.cy
= preferred_mode
->height
;
6516 signal_info
->totalSize
.cx
= preferred_mode
->width
;
6517 signal_info
->totalSize
.cy
= preferred_mode
->height
;
6518 signal_info
->videoStandard
= D3DKMDT_VSS_OTHER
;
6519 if (!(found_mode
->dmFields
& DM_DISPLAYFLAGS
))
6520 signal_info
->scanLineOrdering
= DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED
;
6521 else if (found_mode
->dmDisplayFlags
& DM_INTERLACED
)
6522 signal_info
->scanLineOrdering
= DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED
;
6524 signal_info
->scanLineOrdering
= DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE
;
6525 ret
= STATUS_SUCCESS
;
6529 unlock_display_devices();
6532 case DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME
:
6534 DISPLAYCONFIG_ADAPTER_NAME
*adapter_name
= (DISPLAYCONFIG_ADAPTER_NAME
*)packet
;
6536 FIXME( "DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME stub.\n" );
6538 if (packet
->size
< sizeof(*adapter_name
))
6539 return STATUS_INVALID_PARAMETER
;
6541 return STATUS_NOT_SUPPORTED
;
6543 case DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE
:
6544 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE
:
6545 case DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION
:
6546 case DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION
:
6547 case DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO
:
6548 case DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE
:
6549 case DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL
:
6551 FIXME( "Unimplemented packet type %u.\n", packet
->type
);
6552 return STATUS_INVALID_PARAMETER
;