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
.Length
= name
.MaximumLength
= asciiz_to_unicode( bufferW
, buffer
);
455 InitializeObjectAttributes( &attr
, &name
, OBJ_OPENIF
, NULL
, NULL
);
456 if (NtCreateMutant( &mutex
, MUTEX_ALL_ACCESS
, &attr
, FALSE
) < 0) return 0;
457 NtWaitForSingleObject( mutex
, FALSE
, NULL
);
461 static void release_display_device_init_mutex( HANDLE mutex
)
463 NtReleaseMutant( mutex
, NULL
);
467 static struct adapter
*adapter_acquire( struct adapter
*adapter
)
469 InterlockedIncrement( &adapter
->refcount
);
473 static void adapter_release( struct adapter
*adapter
)
475 if (!InterlockedDecrement( &adapter
->refcount
))
477 free( adapter
->modes
);
482 C_ASSERT(sizeof(DEVMODEW
) - offsetof(DEVMODEW
, dmFields
) == 0x94);
484 static void get_monitor_info_from_edid( struct edid_monitor_info
*info
, const unsigned char *edid
, unsigned int edid_len
)
492 if (!edid
|| edid_len
< 128) return;
494 w
= (edid
[8] << 8) | edid
[9]; /* Manufacturer ID, big endian. */
495 for (i
= 0; i
< 3; ++i
)
498 if (!d
|| d
- 1 > 'Z' - 'A') return;
499 info
->monitor_id_string
[2 - i
] = 'A' + d
- 1;
503 w
= edid
[10] | (edid
[11] << 8); /* Product code, little endian. */
504 info
->manufacturer
= *(unsigned short *)(edid
+ 8);
505 info
->product_code
= w
;
506 sprintf( info
->monitor_id_string
+ 3, "%04X", w
);
507 info
->flags
= MONITOR_INFO_HAS_MONITOR_ID
;
508 TRACE( "Monitor id %s.\n", info
->monitor_id_string
);
510 for (i
= 0; i
< 4; ++i
)
512 if (edid
[54 + i
* 18] || edid
[54 + i
* 18 + 1])
514 /* Detailed timing descriptor. */
515 if (info
->flags
& MONITOR_INFO_HAS_PREFERRED_MODE
) continue;
516 info
->preferred_width
= edid
[54 + i
* 18 + 2] | ((UINT32
)(edid
[54 + i
* 18 + 4] & 0xf0) << 4);
517 info
->preferred_height
= edid
[54 + i
* 18 + 5] | ((UINT32
)(edid
[54 + i
* 18 + 7] & 0xf0) << 4);
518 if (info
->preferred_width
&& info
->preferred_height
)
519 info
->flags
|= MONITOR_INFO_HAS_PREFERRED_MODE
;
522 if (edid
[54 + i
* 18 + 3] != 0xfc) continue;
523 /* "Display name" ASCII descriptor. */
524 s
= (const char *)&edid
[54 + i
* 18 + 5];
525 for (j
= 0; s
[j
] && j
< 13; ++j
)
526 info
->monitor_name
[j
] = s
[j
];
527 while (j
&& isspace(s
[j
- 1])) --j
;
528 info
->monitor_name
[j
] = 0;
529 info
->flags
|= MONITOR_INFO_HAS_MONITOR_NAME
;
534 static BOOL
write_adapter_mode( HKEY adapter_key
, UINT index
, const DEVMODEW
*mode
)
536 WCHAR bufferW
[MAX_PATH
] = {0};
537 char buffer
[MAX_PATH
];
539 sprintf( buffer
, "Modes\\%08X", index
);
540 asciiz_to_unicode( bufferW
, buffer
);
541 return set_reg_value( adapter_key
, bufferW
, REG_BINARY
, &mode
->dmFields
, sizeof(*mode
) - offsetof(DEVMODEW
, dmFields
) );
544 static BOOL
read_adapter_mode( HKEY adapter_key
, UINT index
, DEVMODEW
*mode
)
546 char value_buf
[offsetof(KEY_VALUE_PARTIAL_INFORMATION
, Data
[sizeof(*mode
)])];
547 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)value_buf
;
548 WCHAR bufferW
[MAX_PATH
] = {0};
549 char buffer
[MAX_PATH
];
551 sprintf( buffer
, "Modes\\%08X", index
);
552 asciiz_to_unicode( bufferW
, buffer
);
553 if (!query_reg_value( adapter_key
, bufferW
, value
, sizeof(value_buf
) )) return FALSE
;
555 memcpy( &mode
->dmFields
, value
->Data
, sizeof(*mode
) - offsetof(DEVMODEW
, dmFields
) );
559 static BOOL
adapter_get_registry_settings( const struct adapter
*adapter
, DEVMODEW
*mode
)
565 mutex
= get_display_device_init_mutex();
567 if (!config_key
&& !(config_key
= reg_open_key( NULL
, config_keyW
, sizeof(config_keyW
) ))) ret
= FALSE
;
568 else if (!(hkey
= reg_open_key( config_key
, adapter
->config_key
, lstrlenW( adapter
->config_key
) * sizeof(WCHAR
) ))) ret
= FALSE
;
571 ret
= read_adapter_mode( hkey
, ENUM_REGISTRY_SETTINGS
, mode
);
575 release_display_device_init_mutex( mutex
);
579 static BOOL
adapter_set_registry_settings( const struct adapter
*adapter
, const DEVMODEW
*mode
)
585 mutex
= get_display_device_init_mutex();
587 if (!config_key
&& !(config_key
= reg_open_key( NULL
, config_keyW
, sizeof(config_keyW
) ))) ret
= FALSE
;
588 if (!(hkey
= reg_open_key( config_key
, adapter
->config_key
, lstrlenW( adapter
->config_key
) * sizeof(WCHAR
) ))) ret
= FALSE
;
591 ret
= write_adapter_mode( hkey
, ENUM_REGISTRY_SETTINGS
, mode
);
595 release_display_device_init_mutex( mutex
);
599 static BOOL
adapter_get_current_settings( const struct adapter
*adapter
, DEVMODEW
*mode
)
601 BOOL is_primary
= !!(adapter
->dev
.state_flags
& DISPLAY_DEVICE_PRIMARY_DEVICE
);
606 if ((ret
= user_driver
->pGetCurrentDisplaySettings( adapter
->dev
.device_name
, is_primary
, mode
))) return TRUE
;
608 /* default implementation: read current display settings from the registry. */
610 mutex
= get_display_device_init_mutex();
612 if (!config_key
&& !(config_key
= reg_open_key( NULL
, config_keyW
, sizeof(config_keyW
) ))) ret
= FALSE
;
613 else if (!(hkey
= reg_open_key( config_key
, adapter
->config_key
, lstrlenW( adapter
->config_key
) * sizeof(WCHAR
) ))) ret
= FALSE
;
616 ret
= read_adapter_mode( hkey
, ENUM_CURRENT_SETTINGS
, mode
);
620 release_display_device_init_mutex( mutex
);
624 static BOOL
adapter_set_current_settings( const struct adapter
*adapter
, const DEVMODEW
*mode
)
630 mutex
= get_display_device_init_mutex();
632 if (!config_key
&& !(config_key
= reg_open_key( NULL
, config_keyW
, sizeof(config_keyW
) ))) ret
= FALSE
;
633 if (!(hkey
= reg_open_key( config_key
, adapter
->config_key
, lstrlenW( adapter
->config_key
) * sizeof(WCHAR
) ))) ret
= FALSE
;
636 ret
= write_adapter_mode( hkey
, ENUM_CURRENT_SETTINGS
, mode
);
640 release_display_device_init_mutex( mutex
);
644 static int mode_compare(const void *p1
, const void *p2
)
646 BOOL a_interlaced
, b_interlaced
, a_stretched
, b_stretched
;
647 DWORD a_width
, a_height
, b_width
, b_height
;
648 const DEVMODEW
*a
= p1
, *b
= p2
;
651 /* Depth in descending order */
652 if ((ret
= b
->dmBitsPerPel
- a
->dmBitsPerPel
)) return ret
;
654 /* Use the width and height in landscape mode for comparison */
655 if (a
->dmDisplayOrientation
== DMDO_DEFAULT
|| a
->dmDisplayOrientation
== DMDO_180
)
657 a_width
= a
->dmPelsWidth
;
658 a_height
= a
->dmPelsHeight
;
662 a_width
= a
->dmPelsHeight
;
663 a_height
= a
->dmPelsWidth
;
666 if (b
->dmDisplayOrientation
== DMDO_DEFAULT
|| b
->dmDisplayOrientation
== DMDO_180
)
668 b_width
= b
->dmPelsWidth
;
669 b_height
= b
->dmPelsHeight
;
673 b_width
= b
->dmPelsHeight
;
674 b_height
= b
->dmPelsWidth
;
677 /* Width in ascending order */
678 if ((ret
= a_width
- b_width
)) return ret
;
680 /* Height in ascending order */
681 if ((ret
= a_height
- b_height
)) return ret
;
683 /* Frequency in descending order */
684 if ((ret
= b
->dmDisplayFrequency
- a
->dmDisplayFrequency
)) return ret
;
686 /* Orientation in ascending order */
687 if ((ret
= a
->dmDisplayOrientation
- b
->dmDisplayOrientation
)) return ret
;
689 if (!(a
->dmFields
& DM_DISPLAYFLAGS
)) a_interlaced
= FALSE
;
690 else a_interlaced
= !!(a
->dmDisplayFlags
& DM_INTERLACED
);
691 if (!(b
->dmFields
& DM_DISPLAYFLAGS
)) b_interlaced
= FALSE
;
692 else b_interlaced
= !!(b
->dmDisplayFlags
& DM_INTERLACED
);
694 /* Interlaced in ascending order */
695 if ((ret
= a_interlaced
- b_interlaced
)) return ret
;
697 if (!(a
->dmFields
& DM_DISPLAYFIXEDOUTPUT
)) a_stretched
= FALSE
;
698 else a_stretched
= a
->dmDisplayFixedOutput
== DMDFO_STRETCH
;
699 if (!(b
->dmFields
& DM_DISPLAYFIXEDOUTPUT
)) b_stretched
= FALSE
;
700 else b_stretched
= b
->dmDisplayFixedOutput
== DMDFO_STRETCH
;
702 /* Stretched in ascending order */
703 if ((ret
= a_stretched
- b_stretched
)) return ret
;
708 static unsigned int query_reg_subkey_value( HKEY hkey
, const WCHAR
*name
, unsigned int name_size
,
709 KEY_VALUE_PARTIAL_INFORMATION
*value
, unsigned int size
)
713 if (!(subkey
= reg_open_key( hkey
, name
, name_size
))) return 0;
714 size
= query_reg_value( subkey
, NULL
, value
, size
);
719 static BOOL
read_display_adapter_settings( unsigned int index
, struct adapter
*info
)
722 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
723 WCHAR
*value_str
= (WCHAR
*)value
->Data
;
728 if (!enum_key
&& !(enum_key
= reg_open_key( NULL
, enum_keyW
, sizeof(enum_keyW
) )))
732 sprintf( buffer
, "\\Device\\Video%d", index
);
733 size
= query_reg_ascii_value( video_key
, buffer
, value
, sizeof(buffer
) );
734 if (!size
|| value
->Type
!= REG_SZ
||
735 value
->DataLength
<= sizeof("\\Registry\\Machine\\") * sizeof(WCHAR
))
739 memcpy( info
->dev
.device_key
, value_str
, value
->DataLength
);
740 info
->config_key
= info
->dev
.device_key
+ sizeof("\\Registry\\Machine\\") - 1;
742 if (!(hkey
= reg_open_key( NULL
, value_str
, value
->DataLength
- sizeof(WCHAR
) )))
746 if (query_reg_value( hkey
, driver_descW
, value
, sizeof(buffer
) ) && value
->Type
== REG_SZ
)
747 memcpy( info
->dev
.device_string
, value_str
, value
->DataLength
);
751 sprintf( buffer
, "\\\\.\\DISPLAY%d", index
+ 1 );
752 asciiz_to_unicode( info
->dev
.device_name
, buffer
);
754 if (!(hkey
= reg_open_key( config_key
, info
->config_key
,
755 lstrlenW( info
->config_key
) * sizeof(WCHAR
) )))
759 if (query_reg_value( hkey
, state_flagsW
, value
, sizeof(buffer
) ) && value
->Type
== REG_DWORD
)
760 info
->dev
.state_flags
= *(const DWORD
*)value
->Data
;
763 info
->dev
.interface_name
[0] = 0;
766 if (query_reg_value( hkey
, mode_countW
, value
, sizeof(buffer
) ) && value
->Type
== REG_DWORD
)
767 info
->mode_count
= *(const DWORD
*)value
->Data
;
769 /* Modes, allocate an extra mode for easier iteration */
770 if ((info
->modes
= calloc( info
->mode_count
+ 1, sizeof(DEVMODEW
) )))
772 for (i
= 0, mode
= info
->modes
; i
< info
->mode_count
; i
++)
774 mode
->dmSize
= offsetof(DEVMODEW
, dmICMMethod
);
775 if (!read_adapter_mode( hkey
, i
, mode
)) break;
776 mode
= NEXT_DEVMODEW(mode
);
778 info
->mode_count
= i
;
780 qsort(info
->modes
, info
->mode_count
, sizeof(*info
->modes
) + info
->modes
->dmDriverExtra
, mode_compare
);
784 size
= query_reg_value( hkey
, gpu_idW
, value
, sizeof(buffer
) );
786 if (!size
|| value
->Type
!= REG_SZ
|| !info
->mode_count
|| !info
->modes
) return FALSE
;
788 if (!(hkey
= reg_open_key( enum_key
, value_str
, value
->DataLength
- sizeof(WCHAR
) )))
791 size
= query_reg_subkey_value( hkey
, devpropkey_gpu_luidW
, sizeof(devpropkey_gpu_luidW
), value
, sizeof(buffer
) );
792 if (size
!= sizeof(info
->gpu_luid
))
797 memcpy( &info
->gpu_luid
, value
->Data
, sizeof(info
->gpu_luid
) );
799 size
= query_reg_value( hkey
, hardware_idW
, value
, sizeof(buffer
) );
801 if (!size
|| (value
->Type
!= REG_SZ
&& value
->Type
!= REG_MULTI_SZ
))
804 lstrcpyW( info
->dev
.device_id
, value_str
);
808 static BOOL
read_monitor_settings( struct adapter
*adapter
, UINT index
, struct monitor
*monitor
)
811 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
812 WCHAR
*device_name
, *value_str
= (WCHAR
*)value
->Data
, *ptr
;
816 monitor
->flags
= adapter
->id
? 0 : MONITORINFOF_PRIMARY
;
819 sprintf( buffer
, "\\\\.\\DISPLAY%d\\Monitor%d", adapter
->id
+ 1, index
);
820 asciiz_to_unicode( monitor
->dev
.device_name
, buffer
);
822 if (!(hkey
= reg_open_key( config_key
, adapter
->config_key
,
823 lstrlenW( adapter
->config_key
) * sizeof(WCHAR
) )))
827 sprintf( buffer
, "MonitorID%u", index
);
828 size
= query_reg_ascii_value( hkey
, buffer
, value
, sizeof(buffer
) );
830 if (!size
|| value
->Type
!= REG_SZ
) return FALSE
;
831 len
= asciiz_to_unicode( monitor
->dev
.interface_name
, "\\\\\?\\" ) / sizeof(WCHAR
) - 1;
832 memcpy( monitor
->dev
.interface_name
+ len
, value_str
, value
->DataLength
- sizeof(WCHAR
) );
833 len
+= value
->DataLength
/ sizeof(WCHAR
) - 1;
834 monitor
->dev
.interface_name
[len
++] = '#';
835 memcpy( monitor
->dev
.interface_name
+ len
, guid_devinterface_monitorW
,
836 sizeof(guid_devinterface_monitorW
) );
838 /* Replace '\\' with '#' after prefix */
839 for (ptr
= monitor
->dev
.interface_name
+ ARRAYSIZE("\\\\\?\\") - 1; *ptr
; ptr
++)
840 if (*ptr
== '\\') *ptr
= '#';
842 if (!(hkey
= reg_open_key( enum_key
, value_str
, value
->DataLength
- sizeof(WCHAR
) )))
845 /* StateFlags, WINE_DEVPROPKEY_MONITOR_STATEFLAGS */
846 size
= query_reg_subkey_value( hkey
, wine_devpropkey_monitor_stateflagsW
,
847 sizeof(wine_devpropkey_monitor_stateflagsW
),
848 value
, sizeof(buffer
) );
849 if (size
!= sizeof(monitor
->dev
.state_flags
))
854 monitor
->dev
.state_flags
= *(const DWORD
*)value
->Data
;
857 size
= query_reg_subkey_value( hkey
, devpropkey_monitor_output_idW
,
858 sizeof(devpropkey_monitor_output_idW
),
859 value
, sizeof(buffer
) );
860 if (size
!= sizeof(monitor
->output_id
))
865 monitor
->output_id
= *(const unsigned int *)value
->Data
;
867 /* rc_monitor, WINE_DEVPROPKEY_MONITOR_RCMONITOR */
868 size
= query_reg_subkey_value( hkey
, wine_devpropkey_monitor_rcmonitorW
,
869 sizeof(wine_devpropkey_monitor_rcmonitorW
),
870 value
, sizeof(buffer
) );
871 if (size
!= sizeof(monitor
->rc_monitor
))
876 monitor
->rc_monitor
= *(const RECT
*)value
->Data
;
878 /* rc_work, WINE_DEVPROPKEY_MONITOR_RCWORK */
879 size
= query_reg_subkey_value( hkey
, wine_devpropkey_monitor_rcworkW
,
880 sizeof(wine_devpropkey_monitor_rcworkW
),
881 value
, sizeof(buffer
) );
882 if (size
!= sizeof(monitor
->rc_work
))
887 monitor
->rc_work
= *(const RECT
*)value
->Data
;
890 if (!query_reg_value( hkey
, device_descW
, value
, sizeof(buffer
) ) || value
->Type
!= REG_SZ
)
895 memcpy( monitor
->dev
.device_string
, value
->Data
, value
->DataLength
);
898 if (!query_reg_value( hkey
, driverW
, value
, sizeof(buffer
) ) || value
->Type
!= REG_SZ
)
903 size
= asciiz_to_unicode( monitor
->dev
.device_key
,
904 "\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\" );
905 device_name
= &monitor
->dev
.device_key
[size
/ sizeof(WCHAR
) - 1];
906 memcpy( device_name
, value_str
, value
->DataLength
);
909 if (!query_reg_value( hkey
, hardware_idW
, value
, sizeof(buffer
) ) ||
910 (value
->Type
!= REG_SZ
&& value
->Type
!= REG_MULTI_SZ
))
915 size
= lstrlenW( value_str
);
916 memcpy( monitor
->dev
.device_id
, value_str
, size
* sizeof(WCHAR
) );
917 monitor
->dev
.device_id
[size
++] = '\\';
918 lstrcpyW( monitor
->dev
.device_id
+ size
, device_name
);
921 if ((subkey
= reg_open_key( hkey
, device_parametersW
, sizeof(device_parametersW
) )))
923 if (query_reg_value( subkey
, edidW
, value
, sizeof(buffer
) ))
924 get_monitor_info_from_edid( &monitor
->edid_info
, value
->Data
, value
->DataLength
);
932 static void reg_empty_key( HKEY root
, const char *key_name
)
935 KEY_NODE_INFORMATION
*key
= (KEY_NODE_INFORMATION
*)buffer
;
936 KEY_VALUE_FULL_INFORMATION
*value
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
942 hkey
= reg_open_key( root
, bufferW
, asciiz_to_unicode( bufferW
, key_name
) - sizeof(WCHAR
) );
946 while (!NtEnumerateKey( hkey
, 0, KeyNodeInformation
, key
, sizeof(buffer
), &size
))
947 reg_delete_tree( hkey
, key
->Name
, key
->NameLength
);
949 while (!NtEnumerateValueKey( hkey
, 0, KeyValueFullInformation
, value
, sizeof(buffer
), &size
))
951 UNICODE_STRING name
= { value
->NameLength
, value
->NameLength
, value
->Name
};
952 NtDeleteValueKey( hkey
, &name
);
955 if (hkey
!= root
) NtClose( hkey
);
958 static void prepare_devices(void)
961 KEY_NODE_INFORMATION
*key
= (void *)buffer
;
962 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
963 WCHAR
*value_str
= (WCHAR
*)value
->Data
;
967 HKEY hkey
, subkey
, device_key
, prop_key
;
969 if (!enum_key
) enum_key
= reg_create_key( NULL
, enum_keyW
, sizeof(enum_keyW
), 0, NULL
);
970 if (!control_key
) control_key
= reg_create_key( NULL
, control_keyW
, sizeof(control_keyW
), 0, NULL
);
971 if (!video_key
) video_key
= reg_create_key( NULL
, devicemap_video_keyW
, sizeof(devicemap_video_keyW
),
972 REG_OPTION_VOLATILE
, NULL
);
974 /* delete monitors */
975 reg_empty_key( enum_key
, "DISPLAY" );
976 sprintf( buffer
, "Class\\%s", guid_devclass_monitorA
);
977 hkey
= reg_create_key( control_key
, bufferW
, asciiz_to_unicode( bufferW
, buffer
) - sizeof(WCHAR
),
979 reg_empty_key( hkey
, NULL
);
980 set_reg_value( hkey
, classW
, REG_SZ
, monitorW
, sizeof(monitorW
) );
983 /* delete adapters */
984 reg_empty_key( video_key
, NULL
);
987 sprintf( buffer
, "Class\\%s", guid_devclass_displayA
);
988 hkey
= reg_create_key( control_key
, bufferW
, asciiz_to_unicode( bufferW
, buffer
) - sizeof(WCHAR
),
990 reg_empty_key( hkey
, NULL
);
991 set_reg_value( hkey
, classW
, REG_SZ
, displayW
, sizeof(displayW
) );
994 hkey
= reg_open_key( enum_key
, pciW
, sizeof(pciW
) );
996 /* To preserve GPU GUIDs, mark them as not present and delete them in cleanup_devices if needed. */
997 while (!NtEnumerateKey( hkey
, i
++, KeyNodeInformation
, key
, sizeof(buffer
), &size
))
1001 if (!(subkey
= reg_open_key( hkey
, key
->Name
, key
->NameLength
))) continue;
1003 while (!NtEnumerateKey( subkey
, j
++, KeyNodeInformation
, key
, sizeof(buffer
), &size
))
1005 if (!(device_key
= reg_open_key( subkey
, key
->Name
, key
->NameLength
))) continue;
1006 size
= query_reg_value( device_key
, class_guidW
, value
, sizeof(buffer
) );
1007 if (size
!= sizeof(guid_devclass_displayW
) || wcscmp( value_str
, guid_devclass_displayW
))
1009 NtClose( device_key
);
1013 size
= query_reg_value( device_key
, class_guidW
, value
, sizeof(buffer
) );
1014 if (size
== sizeof(guid_devclass_displayW
) &&
1015 !wcscmp( (const WCHAR
*)value
->Data
, guid_devclass_displayW
) &&
1016 (prop_key
= reg_create_key( device_key
, devpropkey_device_ispresentW
,
1017 sizeof(devpropkey_device_ispresentW
), 0, NULL
)))
1019 BOOL present
= FALSE
;
1020 set_reg_value( prop_key
, NULL
, 0xffff0000 | DEVPROP_TYPE_BOOLEAN
,
1021 &present
, sizeof(present
) );
1022 NtClose( prop_key
);
1025 NtClose( device_key
);
1034 static void cleanup_devices(void)
1037 KEY_NODE_INFORMATION
*key
= (void *)buffer
;
1038 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
1039 WCHAR bufferW
[512], *value_str
= (WCHAR
*)value
->Data
;
1042 HKEY hkey
, subkey
, device_key
, prop_key
;
1044 hkey
= reg_open_key( enum_key
, pciW
, sizeof(pciW
) );
1046 while (!NtEnumerateKey( hkey
, i
++, KeyNodeInformation
, key
, sizeof(buffer
), &size
))
1050 if (!(subkey
= reg_open_key( hkey
, key
->Name
, key
->NameLength
))) continue;
1052 while (!NtEnumerateKey( subkey
, j
++, KeyNodeInformation
, key
, sizeof(buffer
), &size
))
1054 BOOL present
= FALSE
;
1056 if (!(device_key
= reg_open_key( subkey
, key
->Name
, key
->NameLength
))) continue;
1057 memcpy( bufferW
, key
->Name
, key
->NameLength
);
1058 bufferW
[key
->NameLength
/ sizeof(WCHAR
)] = 0;
1060 size
= query_reg_value( device_key
, class_guidW
, value
, sizeof(buffer
) );
1061 if (size
!= sizeof(guid_devclass_displayW
) || wcscmp( value_str
, guid_devclass_displayW
))
1063 NtClose( device_key
);
1067 if ((prop_key
= reg_open_key( device_key
, devpropkey_device_ispresentW
,
1068 sizeof(devpropkey_device_ispresentW
) )))
1070 if (query_reg_value( prop_key
, NULL
, value
, sizeof(buffer
) ) == sizeof(BOOL
))
1071 present
= *(const BOOL
*)value
->Data
;
1072 NtClose( prop_key
);
1075 NtClose( device_key
);
1077 if (!present
&& reg_delete_tree( subkey
, bufferW
, lstrlenW( bufferW
) * sizeof(WCHAR
) ))
1087 /* see UuidCreate */
1088 static void uuid_create( GUID
*uuid
)
1091 NtQuerySystemInformation( SystemInterruptInformation
, buf
, sizeof(buf
), NULL
);
1092 memcpy( uuid
, buf
, sizeof(*uuid
) );
1093 uuid
->Data3
&= 0x0fff;
1094 uuid
->Data3
|= (4 << 12);
1095 uuid
->Data4
[0] &= 0x3f;
1096 uuid
->Data4
[0] |= 0x80;
1099 #define TICKSPERSEC 10000000
1100 #define SECSPERDAY 86400
1101 #define DAYSPERQUADRICENTENNIUM (365 * 400 + 97)
1102 #define DAYSPERNORMALQUADRENNIUM (365 * 4 + 1)
1104 static unsigned int format_date( WCHAR
*bufferW
, LONGLONG time
)
1106 int cleaps
, years
, yearday
, months
, days
;
1107 unsigned int day
, month
, year
;
1110 days
= time
/ TICKSPERSEC
/ SECSPERDAY
;
1112 /* compute year, month and day of month, see RtlTimeToTimeFields */
1113 cleaps
= (3 * ((4 * days
+ 1227) / DAYSPERQUADRICENTENNIUM
) + 3) / 4;
1114 days
+= 28188 + cleaps
;
1115 years
= (20 * days
- 2442) / (5 * DAYSPERNORMALQUADRENNIUM
);
1116 yearday
= days
- (years
* DAYSPERNORMALQUADRENNIUM
) / 4;
1117 months
= (64 * yearday
) / 1959;
1121 year
= years
+ 1524;
1125 month
= months
- 13;
1126 year
= years
+ 1525;
1128 day
= yearday
- (1959 * months
) / 64 ;
1130 sprintf( buffer
, "%u-%u-%u", month
, day
, year
);
1131 return asciiz_to_unicode( bufferW
, buffer
);
1134 struct device_manager_ctx
1136 unsigned int gpu_count
;
1137 unsigned int adapter_count
;
1138 unsigned int video_count
;
1139 unsigned int monitor_count
;
1140 unsigned int output_count
;
1141 unsigned int mode_count
;
1149 static void link_device( const WCHAR
*instance
, const WCHAR
*class )
1151 unsigned int instance_len
= lstrlenW( instance
), len
;
1152 unsigned int class_len
= lstrlenW( class );
1153 WCHAR buffer
[MAX_PATH
], *ptr
;
1156 static const WCHAR symbolic_linkW
[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
1157 static const WCHAR hashW
[] = {'#'};
1159 len
= asciiz_to_unicode( buffer
, "DeviceClasses\\" ) / sizeof(WCHAR
) - 1;
1160 memcpy( buffer
+ len
, class, class_len
* sizeof(WCHAR
) );
1162 len
+= asciiz_to_unicode( buffer
+ len
, "\\##?#" ) / sizeof(WCHAR
) - 1;
1163 memcpy( buffer
+ len
, instance
, instance_len
* sizeof(WCHAR
) );
1164 for (ptr
= buffer
+ len
; *ptr
; ptr
++) if (*ptr
== '\\') *ptr
= '#';
1165 len
+= instance_len
;
1166 buffer
[len
++] = '#';
1167 memcpy( buffer
+ len
, class, class_len
* sizeof(WCHAR
) );
1169 hkey
= reg_create_key( control_key
, buffer
, len
* sizeof(WCHAR
), 0, NULL
);
1171 set_reg_value( hkey
, device_instanceW
, REG_SZ
, instance
, (instance_len
+ 1) * sizeof(WCHAR
) );
1173 subkey
= reg_create_key( hkey
, hashW
, sizeof(hashW
), REG_OPTION_VOLATILE
, NULL
);
1177 len
= asciiz_to_unicode( buffer
, "\\\\?\\" ) / sizeof(WCHAR
) - 1;
1178 memcpy( buffer
+ len
, instance
, (instance_len
+ 1) * sizeof(WCHAR
) );
1179 len
+= instance_len
;
1180 memcpy( buffer
+ len
, class, (class_len
+ 1) * sizeof(WCHAR
) );
1181 len
+= class_len
+ 1;
1182 for (ptr
= buffer
+ 4; *ptr
; ptr
++) if (*ptr
== '\\') *ptr
= '#';
1183 set_reg_value( hkey
, symbolic_linkW
, REG_SZ
, buffer
, len
* sizeof(WCHAR
) );
1185 if ((subkey
= reg_create_key( hkey
, controlW
, sizeof(controlW
), REG_OPTION_VOLATILE
, NULL
)))
1187 const DWORD linked
= 1;
1188 set_reg_value( subkey
, linkedW
, REG_DWORD
, &linked
, sizeof(linked
) );
1193 static void add_gpu( const struct gdi_gpu
*gpu
, void *param
)
1195 struct device_manager_ctx
*ctx
= param
;
1199 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
1200 unsigned int gpu_index
, size
;
1204 static const BOOL present
= TRUE
;
1205 static const WCHAR wine_adapterW
[] = {'W','i','n','e',' ','A','d','a','p','t','e','r',0};
1206 static const WCHAR video_idW
[] = {'V','i','d','e','o','I','D',0};
1207 static const WCHAR driver_date_dataW
[] =
1208 {'D','r','i','v','e','r','D','a','t','e','D','a','t','a',0};
1209 static const WCHAR adapter_stringW
[] =
1210 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n',
1211 '.','A','d','a','p','t','e','r','S','t','r','i','n','g',0};
1212 static const WCHAR bios_stringW
[] =
1213 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n','.',
1214 'B','i','o','s','S','t','r','i','n','g',0};
1215 static const WCHAR chip_typeW
[] =
1216 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n','.',
1217 'C','h','i','p','T','y','p','e',0};
1218 static const WCHAR dac_typeW
[] =
1219 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n','.',
1220 'D','a','c','T','y','p','e',0};
1221 static const WCHAR ramdacW
[] =
1222 {'I','n','t','e','r','g','r','a','t','e','d',' ','R','A','M','D','A','C',0};
1223 static const WCHAR driver_dateW
[] = {'D','r','i','v','e','r','D','a','t','e',0};
1225 TRACE( "%s %04X %04X %08X %02X\n", debugstr_w(gpu
->name
),
1226 gpu
->vendor_id
, gpu
->device_id
, gpu
->subsys_id
, gpu
->revision_id
);
1228 gpu_index
= ctx
->gpu_count
++;
1229 ctx
->adapter_count
= 0;
1230 ctx
->monitor_count
= 0;
1231 ctx
->mode_count
= 0;
1233 if (!enum_key
&& !(enum_key
= reg_create_key( NULL
, enum_keyW
, sizeof(enum_keyW
), 0, NULL
)))
1238 ctx
->mutex
= get_display_device_init_mutex();
1239 pthread_mutex_lock( &display_lock
);
1243 sprintf( buffer
, "PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X\\%08X",
1244 gpu
->vendor_id
, gpu
->device_id
, gpu
->subsys_id
, gpu
->revision_id
, gpu_index
);
1245 size
= asciiz_to_unicode( ctx
->gpuid
, buffer
);
1246 if (!(hkey
= reg_create_key( enum_key
, ctx
->gpuid
, size
- sizeof(WCHAR
), 0, NULL
))) return;
1248 set_reg_value( hkey
, classW
, REG_SZ
, displayW
, sizeof(displayW
) );
1249 set_reg_value( hkey
, class_guidW
, REG_SZ
, guid_devclass_displayW
,
1250 sizeof(guid_devclass_displayW
) );
1251 sprintf( buffer
, "%s\\%04X", guid_devclass_displayA
, gpu_index
);
1252 set_reg_value( hkey
, driverW
, REG_SZ
, bufferW
, asciiz_to_unicode( bufferW
, buffer
));
1254 sprintf( buffer
, "PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X",
1255 gpu
->vendor_id
, gpu
->device_id
, gpu
->subsys_id
, gpu
->revision_id
);
1256 size
= asciiz_to_unicode( bufferW
, buffer
);
1257 bufferW
[size
/ sizeof(WCHAR
)] = 0; /* for REG_MULTI_SZ */
1258 set_reg_value( hkey
, hardware_idW
, REG_MULTI_SZ
, bufferW
, size
+ sizeof(WCHAR
) );
1260 if ((subkey
= reg_create_key( hkey
, devpkey_device_matching_device_id
,
1261 sizeof(devpkey_device_matching_device_id
), 0, NULL
)))
1263 if (gpu
->vendor_id
&& gpu
->device_id
)
1264 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_STRING
, bufferW
, size
);
1266 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_STRING
, bufferW
,
1267 asciiz_to_unicode( bufferW
, "ROOT\\BasicRender" ));
1271 if (gpu
->vendor_id
&& gpu
->device_id
)
1273 if ((subkey
= reg_create_key( hkey
, devpkey_device_bus_number
,
1274 sizeof(devpkey_device_bus_number
), 0, NULL
)))
1276 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_UINT32
,
1277 &gpu_index
, sizeof(gpu_index
) );
1282 if ((subkey
= reg_create_key( hkey
, devpkey_device_removal_policy
,
1283 sizeof(devpkey_device_removal_policy
), 0, NULL
)))
1285 unsigned int removal_policy
= CM_REMOVAL_POLICY_EXPECT_NO_REMOVAL
;
1287 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_UINT32
,
1288 &removal_policy
, sizeof(removal_policy
) );
1293 if (!desc
[0]) desc
= wine_adapterW
;
1294 set_reg_value( hkey
, device_descW
, REG_SZ
, desc
, (lstrlenW( desc
) + 1) * sizeof(WCHAR
) );
1296 if ((subkey
= reg_create_key( hkey
, device_parametersW
, sizeof(device_parametersW
), 0, NULL
)))
1298 if (!query_reg_value( subkey
, video_idW
, value
, sizeof(buffer
) ))
1301 uuid_create( &guid
);
1302 sprintf( buffer
, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
1303 (unsigned int)guid
.Data1
, guid
.Data2
, guid
.Data3
, guid
.Data4
[0], guid
.Data4
[1], guid
.Data4
[2],
1304 guid
.Data4
[3], guid
.Data4
[4], guid
.Data4
[5], guid
.Data4
[6], guid
.Data4
[7] );
1305 size
= asciiz_to_unicode( ctx
->gpu_guid
, buffer
);
1306 TRACE( "created guid %s\n", debugstr_w(ctx
->gpu_guid
) );
1307 set_reg_value( subkey
, video_idW
, REG_SZ
, ctx
->gpu_guid
, size
);
1311 memcpy( ctx
->gpu_guid
, value
->Data
, value
->DataLength
);
1312 TRACE( "got guid %s\n", debugstr_w(ctx
->gpu_guid
) );
1317 if ((subkey
= reg_create_key( hkey
, devpropkey_gpu_vulkan_uuidW
,
1318 sizeof(devpropkey_gpu_vulkan_uuidW
), 0, NULL
)))
1320 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_GUID
,
1321 &gpu
->vulkan_uuid
, sizeof(gpu
->vulkan_uuid
) );
1325 if ((subkey
= reg_create_key( hkey
, devpropkey_device_ispresentW
,
1326 sizeof(devpropkey_device_ispresentW
), 0, NULL
)))
1328 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_BOOLEAN
,
1329 &present
, sizeof(present
) );
1333 if ((subkey
= reg_create_key( hkey
, devpropkey_gpu_luidW
, sizeof(devpropkey_gpu_luidW
), 0, NULL
)))
1335 if (query_reg_value( subkey
, NULL
, value
, sizeof(buffer
) ) != sizeof(LUID
))
1337 NtAllocateLocallyUniqueId( &ctx
->gpu_luid
);
1338 TRACE("allocated luid %08x%08x\n", (int)ctx
->gpu_luid
.HighPart
, (int)ctx
->gpu_luid
.LowPart
);
1339 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_UINT64
,
1340 &ctx
->gpu_luid
, sizeof(ctx
->gpu_luid
) );
1344 memcpy( &ctx
->gpu_luid
, value
->Data
, sizeof(ctx
->gpu_luid
) );
1345 TRACE("got luid %08x%08x\n", (int)ctx
->gpu_luid
.HighPart
, (int)ctx
->gpu_luid
.LowPart
);
1352 sprintf( buffer
, "Class\\%s\\%04X", guid_devclass_displayA
, gpu_index
);
1353 hkey
= reg_create_key( control_key
, bufferW
,
1354 asciiz_to_unicode( bufferW
, buffer
) - sizeof(WCHAR
), 0, NULL
);
1356 NtQuerySystemTime( &ft
);
1357 set_reg_value( hkey
, driver_dateW
, REG_SZ
, bufferW
, format_date( bufferW
, ft
.QuadPart
));
1359 set_reg_value( hkey
, driver_date_dataW
, REG_BINARY
, &ft
, sizeof(ft
) );
1361 size
= (lstrlenW( desc
) + 1) * sizeof(WCHAR
);
1362 set_reg_value( hkey
, driver_descW
, REG_SZ
, desc
, size
);
1363 set_reg_value( hkey
, adapter_stringW
, REG_BINARY
, desc
, size
);
1364 set_reg_value( hkey
, bios_stringW
, REG_BINARY
, desc
, size
);
1365 set_reg_value( hkey
, chip_typeW
, REG_BINARY
, desc
, size
);
1366 set_reg_value( hkey
, dac_typeW
, REG_BINARY
, ramdacW
, sizeof(ramdacW
) );
1370 link_device( ctx
->gpuid
, guid_devinterface_display_adapterW
);
1371 link_device( ctx
->gpuid
, guid_display_device_arrivalW
);
1374 static void add_adapter( const struct gdi_adapter
*adapter
, void *param
)
1376 struct device_manager_ctx
*ctx
= param
;
1377 unsigned int adapter_index
, video_index
, len
;
1378 char name
[64], buffer
[MAX_PATH
];
1379 WCHAR nameW
[64], bufferW
[MAX_PATH
];
1384 if (ctx
->adapter_key
)
1386 NtClose( ctx
->adapter_key
);
1387 ctx
->adapter_key
= NULL
;
1390 adapter_index
= ctx
->adapter_count
++;
1391 video_index
= ctx
->video_count
++;
1392 ctx
->monitor_count
= 0;
1393 ctx
->mode_count
= 0;
1395 len
= asciiz_to_unicode( bufferW
, "\\Registry\\Machine\\System\\CurrentControlSet\\"
1396 "Control\\Video\\" ) / sizeof(WCHAR
) - 1;
1397 lstrcpyW( bufferW
+ len
, ctx
->gpu_guid
);
1398 len
+= lstrlenW( bufferW
+ len
);
1399 sprintf( buffer
, "\\%04x", adapter_index
);
1400 len
+= asciiz_to_unicode( bufferW
+ len
, buffer
) / sizeof(WCHAR
) - 1;
1401 hkey
= reg_create_key( NULL
, bufferW
, len
* sizeof(WCHAR
),
1402 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
, NULL
);
1403 if (!hkey
) hkey
= reg_create_key( NULL
, bufferW
, len
* sizeof(WCHAR
),
1404 REG_OPTION_VOLATILE
| REG_OPTION_OPEN_LINK
, NULL
);
1406 sprintf( name
, "\\Device\\Video%u", video_index
);
1407 asciiz_to_unicode( nameW
, name
);
1408 set_reg_value( video_key
, nameW
, REG_SZ
, bufferW
, (lstrlenW( bufferW
) + 1) * sizeof(WCHAR
) );
1412 sprintf( buffer
, "\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\"
1413 "%s\\%04X", guid_devclass_displayA
, ctx
->gpu_count
- 1 );
1414 len
= asciiz_to_unicode( bufferW
, buffer
) - sizeof(WCHAR
);
1415 set_reg_value( hkey
, symbolic_link_valueW
, REG_LINK
, bufferW
, len
);
1418 else ERR( "failed to create link key\n" );
1420 /* Following information is Wine specific, it doesn't really exist on Windows. */
1421 len
= asciiz_to_unicode( bufferW
, "System\\CurrentControlSet\\Control\\Video\\" )
1422 / sizeof(WCHAR
) - 1;
1423 lstrcpyW( bufferW
+ len
, ctx
->gpu_guid
);
1424 len
+= lstrlenW( bufferW
+ len
);
1425 sprintf( buffer
, "\\%04x", adapter_index
);
1426 len
+= asciiz_to_unicode( bufferW
+ len
, buffer
) / sizeof(WCHAR
) - 1;
1427 ctx
->adapter_key
= reg_create_key( config_key
, bufferW
, len
* sizeof(WCHAR
),
1428 REG_OPTION_VOLATILE
, NULL
);
1430 set_reg_value( ctx
->adapter_key
, gpu_idW
, REG_SZ
, ctx
->gpuid
,
1431 (lstrlenW( ctx
->gpuid
) + 1) * sizeof(WCHAR
) );
1432 set_reg_value( ctx
->adapter_key
, state_flagsW
, REG_DWORD
, &adapter
->state_flags
,
1433 sizeof(adapter
->state_flags
) );
1436 static void add_monitor( const struct gdi_monitor
*monitor
, void *param
)
1438 struct device_manager_ctx
*ctx
= param
;
1439 char buffer
[MAX_PATH
], instance
[64];
1440 unsigned int monitor_index
, output_index
;
1441 struct edid_monitor_info monitor_info
;
1442 char monitor_id_string
[16];
1443 WCHAR bufferW
[MAX_PATH
];
1447 monitor_index
= ctx
->monitor_count
++;
1448 output_index
= ctx
->output_count
++;
1450 TRACE( "%u %s %s\n", monitor_index
, wine_dbgstr_rect(&monitor
->rc_monitor
), wine_dbgstr_rect(&monitor
->rc_work
) );
1452 get_monitor_info_from_edid( &monitor_info
, monitor
->edid
, monitor
->edid_len
);
1453 if (monitor_info
.flags
& MONITOR_INFO_HAS_MONITOR_ID
)
1454 strcpy( monitor_id_string
, monitor_info
.monitor_id_string
);
1456 strcpy( monitor_id_string
, "Default_Monitor" );
1458 sprintf( buffer
, "MonitorID%u", monitor_index
);
1459 sprintf( instance
, "DISPLAY\\%s\\%04X&%04X", monitor_id_string
, ctx
->video_count
- 1, monitor_index
);
1460 set_reg_ascii_value( ctx
->adapter_key
, buffer
, instance
);
1462 hkey
= reg_create_key( enum_key
, bufferW
, asciiz_to_unicode( bufferW
, instance
) - sizeof(WCHAR
),
1466 link_device( bufferW
, guid_devinterface_monitorW
);
1468 asciiz_to_unicode( bufferW
, "Generic Non-PnP Monitor" );
1469 set_reg_value( hkey
, device_descW
, REG_SZ
, bufferW
, (lstrlenW( bufferW
) + 1) * sizeof(WCHAR
) );
1471 set_reg_value( hkey
, classW
, REG_SZ
, monitorW
, sizeof(monitorW
) );
1472 sprintf( buffer
, "%s\\%04X", guid_devclass_monitorA
, output_index
);
1473 set_reg_ascii_value( hkey
, "Driver", buffer
);
1474 set_reg_value( hkey
, class_guidW
, REG_SZ
, guid_devclass_monitorW
, sizeof(guid_devclass_monitorW
) );
1476 sprintf( buffer
, "MONITOR\\%s", monitor_id_string
);
1477 len
= asciiz_to_unicode( bufferW
, buffer
);
1478 bufferW
[len
/ sizeof(WCHAR
)] = 0;
1479 set_reg_value( hkey
, hardware_idW
, REG_MULTI_SZ
, bufferW
, len
+ sizeof(WCHAR
) );
1481 if ((subkey
= reg_create_key( hkey
, device_parametersW
, sizeof(device_parametersW
), 0, NULL
)))
1483 static const WCHAR bad_edidW
[] = {'B','A','D','_','E','D','I','D',0};
1485 if (monitor
->edid_len
)
1486 set_reg_value( subkey
, edidW
, REG_BINARY
, monitor
->edid
, monitor
->edid_len
);
1488 set_reg_value( subkey
, bad_edidW
, REG_BINARY
, NULL
, 0 );
1493 if ((subkey
= reg_create_key( hkey
, wine_devpropkey_monitor_stateflagsW
,
1494 sizeof(wine_devpropkey_monitor_stateflagsW
), 0, NULL
)))
1496 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_UINT32
, &monitor
->state_flags
,
1497 sizeof(monitor
->state_flags
) );
1501 /* WINE_DEVPROPKEY_MONITOR_RCMONITOR */
1502 if ((subkey
= reg_create_key( hkey
, wine_devpropkey_monitor_rcmonitorW
,
1503 sizeof(wine_devpropkey_monitor_rcmonitorW
), 0, NULL
)))
1505 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_BINARY
, &monitor
->rc_monitor
,
1506 sizeof(monitor
->rc_monitor
) );
1510 /* WINE_DEVPROPKEY_MONITOR_RCWORK */
1511 if ((subkey
= reg_create_key( hkey
, wine_devpropkey_monitor_rcworkW
,
1512 sizeof(wine_devpropkey_monitor_rcworkW
), 0, NULL
)))
1514 TRACE( "rc_work %s\n", wine_dbgstr_rect(&monitor
->rc_work
) );
1515 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_BINARY
, &monitor
->rc_work
,
1516 sizeof(monitor
->rc_work
) );
1520 /* WINE_DEVPROPKEY_MONITOR_ADAPTERNAME */
1521 if ((subkey
= reg_create_key( hkey
, wine_devpropkey_monitor_adapternameW
,
1522 sizeof(wine_devpropkey_monitor_adapternameW
), 0, NULL
)))
1524 sprintf( buffer
, "\\\\.\\DISPLAY%u", ctx
->video_count
);
1525 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_STRING
, bufferW
,
1526 asciiz_to_unicode( bufferW
, buffer
));
1530 /* DEVPROPKEY_MONITOR_GPU_LUID */
1531 if ((subkey
= reg_create_key( hkey
, devpropkey_monitor_gpu_luidW
,
1532 sizeof(devpropkey_monitor_gpu_luidW
), 0, NULL
)))
1534 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_INT64
,
1535 &ctx
->gpu_luid
, sizeof(ctx
->gpu_luid
) );
1539 /* DEVPROPKEY_MONITOR_OUTPUT_ID */
1540 if ((subkey
= reg_create_key( hkey
, devpropkey_monitor_output_idW
,
1541 sizeof(devpropkey_monitor_output_idW
), 0, NULL
)))
1543 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_UINT32
,
1544 &output_index
, sizeof(output_index
) );
1550 sprintf( buffer
, "Class\\%s\\%04X", guid_devclass_monitorA
, output_index
);
1551 hkey
= reg_create_key( control_key
, bufferW
,
1552 asciiz_to_unicode( bufferW
, buffer
) - sizeof(WCHAR
), 0, NULL
);
1553 if (hkey
) NtClose( hkey
);
1556 static void add_mode( const DEVMODEW
*mode
, BOOL current
, void *param
)
1558 struct device_manager_ctx
*ctx
= param
;
1559 DEVMODEW nopos_mode
;
1561 if (!ctx
->adapter_count
)
1563 static const struct gdi_adapter default_adapter
=
1565 .state_flags
= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
| DISPLAY_DEVICE_PRIMARY_DEVICE
| DISPLAY_DEVICE_VGA_COMPATIBLE
,
1567 TRACE( "adding default fake adapter\n" );
1568 add_adapter( &default_adapter
, ctx
);
1572 nopos_mode
.dmPosition
.x
= 0;
1573 nopos_mode
.dmPosition
.y
= 0;
1574 nopos_mode
.dmFields
&= ~DM_POSITION
;
1576 if (write_adapter_mode( ctx
->adapter_key
, ctx
->mode_count
, &nopos_mode
))
1579 set_reg_value( ctx
->adapter_key
, mode_countW
, REG_DWORD
, &ctx
->mode_count
, sizeof(ctx
->mode_count
) );
1582 if (!read_adapter_mode( ctx
->adapter_key
, ENUM_REGISTRY_SETTINGS
, &nopos_mode
))
1583 write_adapter_mode( ctx
->adapter_key
, ENUM_REGISTRY_SETTINGS
, mode
);
1584 write_adapter_mode( ctx
->adapter_key
, ENUM_CURRENT_SETTINGS
, mode
);
1589 static const struct gdi_device_manager device_manager
=
1597 static void release_display_manager_ctx( struct device_manager_ctx
*ctx
)
1601 pthread_mutex_unlock( &display_lock
);
1602 release_display_device_init_mutex( ctx
->mutex
);
1604 if (ctx
->adapter_key
)
1606 NtClose( ctx
->adapter_key
);
1607 last_query_display_time
= 0;
1609 if (ctx
->gpu_count
) cleanup_devices();
1612 static void clear_display_devices(void)
1614 struct adapter
*adapter
;
1615 struct monitor
*monitor
;
1617 if (list_head( &monitors
) == &virtual_monitor
.entry
)
1619 list_init( &monitors
);
1623 while (!list_empty( &monitors
))
1625 monitor
= LIST_ENTRY( list_head( &monitors
), struct monitor
, entry
);
1626 adapter_release( monitor
->adapter
);
1627 list_remove( &monitor
->entry
);
1631 while (!list_empty( &adapters
))
1633 adapter
= LIST_ENTRY( list_head( &adapters
), struct adapter
, entry
);
1634 list_remove( &adapter
->entry
);
1635 adapter_release( adapter
);
1639 static BOOL
update_display_cache_from_registry(void)
1641 DWORD adapter_id
, monitor_id
, monitor_count
= 0, size
;
1642 KEY_BASIC_INFORMATION key
;
1643 struct adapter
*adapter
;
1644 struct monitor
*monitor
, *monitor2
;
1645 HANDLE mutex
= NULL
;
1649 /* If user driver did initialize the registry, then exit */
1650 if (!video_key
&& !(video_key
= reg_open_key( NULL
, devicemap_video_keyW
,
1651 sizeof(devicemap_video_keyW
) )))
1654 status
= NtQueryKey( video_key
, KeyBasicInformation
, &key
,
1655 offsetof(KEY_BASIC_INFORMATION
, Name
), &size
);
1656 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
)
1659 if (key
.LastWriteTime
.QuadPart
<= last_query_display_time
) return TRUE
;
1661 mutex
= get_display_device_init_mutex();
1662 pthread_mutex_lock( &display_lock
);
1664 clear_display_devices();
1666 for (adapter_id
= 0;; adapter_id
++)
1668 if (!(adapter
= calloc( 1, sizeof(*adapter
) ))) break;
1669 adapter
->refcount
= 1;
1670 adapter
->id
= adapter_id
;
1672 if (!read_display_adapter_settings( adapter_id
, adapter
))
1674 adapter_release( adapter
);
1678 list_add_tail( &adapters
, &adapter
->entry
);
1679 for (monitor_id
= 0;; monitor_id
++)
1681 if (!(monitor
= calloc( 1, sizeof(*monitor
) ))) break;
1682 if (!read_monitor_settings( adapter
, monitor_id
, monitor
))
1688 monitor
->id
= monitor_id
;
1689 monitor
->adapter
= adapter_acquire( adapter
);
1691 LIST_FOR_EACH_ENTRY(monitor2
, &monitors
, struct monitor
, entry
)
1693 if (EqualRect(&monitor2
->rc_monitor
, &monitor
->rc_monitor
))
1695 monitor
->is_clone
= TRUE
;
1700 monitor
->handle
= UlongToHandle( ++monitor_count
);
1701 list_add_tail( &monitors
, &monitor
->entry
);
1705 if ((ret
= !list_empty( &adapters
) && !list_empty( &monitors
)))
1706 last_query_display_time
= key
.LastWriteTime
.QuadPart
;
1707 pthread_mutex_unlock( &display_lock
);
1708 release_display_device_init_mutex( mutex
);
1712 static BOOL
is_same_devmode( const DEVMODEW
*a
, const DEVMODEW
*b
)
1714 return a
->dmDisplayOrientation
== b
->dmDisplayOrientation
&&
1715 a
->dmBitsPerPel
== b
->dmBitsPerPel
&&
1716 a
->dmPelsWidth
== b
->dmPelsWidth
&&
1717 a
->dmPelsHeight
== b
->dmPelsHeight
&&
1718 a
->dmDisplayFrequency
== b
->dmDisplayFrequency
;
1721 static BOOL
update_display_cache( BOOL force
)
1723 HWINSTA winstation
= NtUserGetProcessWindowStation();
1724 struct device_manager_ctx ctx
= {0};
1725 USEROBJECTFLAGS flags
;
1727 /* services do not have any adapters, only a virtual monitor */
1728 if (NtUserGetObjectInformation( winstation
, UOI_FLAGS
, &flags
, sizeof(flags
), NULL
)
1729 && !(flags
.dwFlags
& WSF_VISIBLE
))
1731 pthread_mutex_lock( &display_lock
);
1732 clear_display_devices();
1733 list_add_tail( &monitors
, &virtual_monitor
.entry
);
1734 pthread_mutex_unlock( &display_lock
);
1738 if (!user_driver
->pUpdateDisplayDevices( &device_manager
, force
, &ctx
) && force
)
1740 /* default implementation: expose an adapter and a monitor with a few standard modes,
1741 * and read / write current display settings from / to the registry.
1743 static const DEVMODEW modes
[] =
1745 { .dmFields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
,
1746 .dmBitsPerPel
= 32, .dmPelsWidth
= 640, .dmPelsHeight
= 480, .dmDisplayFrequency
= 60, },
1747 { .dmFields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
,
1748 .dmBitsPerPel
= 32, .dmPelsWidth
= 800, .dmPelsHeight
= 600, .dmDisplayFrequency
= 60, },
1749 { .dmFields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
,
1750 .dmBitsPerPel
= 32, .dmPelsWidth
= 1024, .dmPelsHeight
= 768, .dmDisplayFrequency
= 60, },
1751 { .dmFields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
,
1752 .dmBitsPerPel
= 16, .dmPelsWidth
= 640, .dmPelsHeight
= 480, .dmDisplayFrequency
= 60, },
1753 { .dmFields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
,
1754 .dmBitsPerPel
= 16, .dmPelsWidth
= 800, .dmPelsHeight
= 600, .dmDisplayFrequency
= 60, },
1755 { .dmFields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
,
1756 .dmBitsPerPel
= 16, .dmPelsWidth
= 1024, .dmPelsHeight
= 768, .dmDisplayFrequency
= 60, },
1758 static const struct gdi_gpu gpu
;
1759 static const struct gdi_adapter adapter
=
1761 .state_flags
= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
| DISPLAY_DEVICE_PRIMARY_DEVICE
| DISPLAY_DEVICE_VGA_COMPATIBLE
,
1763 struct gdi_monitor monitor
=
1765 .state_flags
= DISPLAY_DEVICE_ACTIVE
| DISPLAY_DEVICE_ATTACHED
,
1767 DEVMODEW mode
= {{0}};
1770 add_gpu( &gpu
, &ctx
);
1771 add_adapter( &adapter
, &ctx
);
1773 if (!read_adapter_mode( ctx
.adapter_key
, ENUM_CURRENT_SETTINGS
, &mode
))
1776 mode
.dmFields
|= DM_POSITION
;
1778 monitor
.rc_monitor
.right
= mode
.dmPelsWidth
;
1779 monitor
.rc_monitor
.bottom
= mode
.dmPelsHeight
;
1780 monitor
.rc_work
.right
= mode
.dmPelsWidth
;
1781 monitor
.rc_work
.bottom
= mode
.dmPelsHeight
;
1783 add_monitor( &monitor
, &ctx
);
1784 for (i
= 0; i
< ARRAY_SIZE(modes
); ++i
)
1786 if (is_same_devmode( modes
+ i
, &mode
)) add_mode( &mode
, TRUE
, &ctx
);
1787 else add_mode( modes
+ i
, FALSE
, &ctx
);
1790 release_display_manager_ctx( &ctx
);
1792 if (!update_display_cache_from_registry())
1796 ERR( "Failed to read display config.\n" );
1802 ERR( "Driver reported devices, but we failed to read them.\n" );
1806 return update_display_cache( TRUE
);
1812 static BOOL
lock_display_devices(void)
1814 if (!update_display_cache( FALSE
)) return FALSE
;
1815 pthread_mutex_lock( &display_lock
);
1819 static void unlock_display_devices(void)
1821 pthread_mutex_unlock( &display_lock
);
1824 static HDC
get_display_dc(void)
1826 pthread_mutex_lock( &display_dc_lock
);
1831 pthread_mutex_unlock( &display_dc_lock
);
1832 dc
= NtGdiOpenDCW( NULL
, NULL
, NULL
, 0, TRUE
, NULL
, NULL
, NULL
);
1833 pthread_mutex_lock( &display_dc_lock
);
1835 NtGdiDeleteObjectApp( dc
);
1842 static void release_display_dc( HDC hdc
)
1844 pthread_mutex_unlock( &display_dc_lock
);
1847 /**********************************************************************
1850 UINT
get_monitor_dpi( HMONITOR monitor
)
1852 /* FIXME: use the monitor DPI instead */
1856 /**********************************************************************
1857 * get_win_monitor_dpi
1859 UINT
get_win_monitor_dpi( HWND hwnd
)
1861 /* FIXME: use the monitor DPI instead */
1865 /**********************************************************************
1866 * get_thread_dpi_awareness
1868 DPI_AWARENESS
get_thread_dpi_awareness(void)
1870 struct ntuser_thread_info
*info
= NtUserGetThreadInfo();
1871 ULONG_PTR context
= info
->dpi_awareness
;
1873 if (!context
) context
= NtUserGetProcessDpiAwarenessContext( NULL
);
1884 case (ULONG_PTR
)DPI_AWARENESS_CONTEXT_UNAWARE
:
1885 case (ULONG_PTR
)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE
:
1886 case (ULONG_PTR
)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
:
1889 return DPI_AWARENESS_INVALID
;
1893 DWORD
get_process_layout(void)
1895 return process_layout
== ~0u ? 0 : process_layout
;
1898 /**********************************************************************
1901 UINT
get_thread_dpi(void)
1903 switch (get_thread_dpi_awareness())
1905 case DPI_AWARENESS_UNAWARE
: return USER_DEFAULT_SCREEN_DPI
;
1906 case DPI_AWARENESS_SYSTEM_AWARE
: return system_dpi
;
1907 default: return 0; /* no scaling */
1911 /* see GetDpiForSystem */
1912 UINT
get_system_dpi(void)
1914 if (get_thread_dpi_awareness() == DPI_AWARENESS_UNAWARE
) return USER_DEFAULT_SCREEN_DPI
;
1918 /* see GetAwarenessFromDpiAwarenessContext */
1919 static DPI_AWARENESS
get_awareness_from_dpi_awareness_context( DPI_AWARENESS_CONTEXT context
)
1921 switch ((ULONG_PTR
)context
)
1929 return (ULONG_PTR
)context
& 3;
1930 case (ULONG_PTR
)DPI_AWARENESS_CONTEXT_UNAWARE
:
1931 case (ULONG_PTR
)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE
:
1932 case (ULONG_PTR
)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
:
1933 return ~(ULONG_PTR
)context
;
1935 return DPI_AWARENESS_INVALID
;
1939 /**********************************************************************
1940 * SetThreadDpiAwarenessContext (win32u.so)
1942 DPI_AWARENESS_CONTEXT WINAPI
SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT context
)
1944 struct ntuser_thread_info
*info
= NtUserGetThreadInfo();
1945 DPI_AWARENESS prev
, val
= get_awareness_from_dpi_awareness_context( context
);
1947 if (val
== DPI_AWARENESS_INVALID
)
1949 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
1952 if (!(prev
= info
->dpi_awareness
))
1954 prev
= NtUserGetProcessDpiAwarenessContext( GetCurrentProcess() ) & 3;
1955 prev
|= 0x80000010; /* restore to process default */
1957 if (((ULONG_PTR
)context
& ~(ULONG_PTR
)0x13) == 0x80000000) info
->dpi_awareness
= 0;
1958 else info
->dpi_awareness
= val
| 0x10;
1959 return ULongToHandle( prev
);
1962 /**********************************************************************
1965 RECT
map_dpi_rect( RECT rect
, UINT dpi_from
, UINT dpi_to
)
1967 if (dpi_from
&& dpi_to
&& dpi_from
!= dpi_to
)
1969 rect
.left
= muldiv( rect
.left
, dpi_to
, dpi_from
);
1970 rect
.top
= muldiv( rect
.top
, dpi_to
, dpi_from
);
1971 rect
.right
= muldiv( rect
.right
, dpi_to
, dpi_from
);
1972 rect
.bottom
= muldiv( rect
.bottom
, dpi_to
, dpi_from
);
1977 /**********************************************************************
1980 POINT
map_dpi_point( POINT pt
, UINT dpi_from
, UINT dpi_to
)
1982 if (dpi_from
&& dpi_to
&& dpi_from
!= dpi_to
)
1984 pt
.x
= muldiv( pt
.x
, dpi_to
, dpi_from
);
1985 pt
.y
= muldiv( pt
.y
, dpi_to
, dpi_from
);
1990 /**********************************************************************
1991 * point_win_to_phys_dpi
1993 static POINT
point_win_to_phys_dpi( HWND hwnd
, POINT pt
)
1995 return map_dpi_point( pt
, get_dpi_for_window( hwnd
), get_win_monitor_dpi( hwnd
) );
1998 /**********************************************************************
1999 * point_phys_to_win_dpi
2001 POINT
point_phys_to_win_dpi( HWND hwnd
, POINT pt
)
2003 return map_dpi_point( pt
, get_win_monitor_dpi( hwnd
), get_dpi_for_window( hwnd
));
2006 /**********************************************************************
2007 * point_thread_to_win_dpi
2009 POINT
point_thread_to_win_dpi( HWND hwnd
, POINT pt
)
2011 UINT dpi
= get_thread_dpi();
2012 if (!dpi
) dpi
= get_win_monitor_dpi( hwnd
);
2013 return map_dpi_point( pt
, dpi
, get_dpi_for_window( hwnd
));
2016 /**********************************************************************
2017 * rect_thread_to_win_dpi
2019 RECT
rect_thread_to_win_dpi( HWND hwnd
, RECT rect
)
2021 UINT dpi
= get_thread_dpi();
2022 if (!dpi
) dpi
= get_win_monitor_dpi( hwnd
);
2023 return map_dpi_rect( rect
, dpi
, get_dpi_for_window( hwnd
) );
2026 /* map value from system dpi to standard 96 dpi for storing in the registry */
2027 static int map_from_system_dpi( int val
)
2029 return muldiv( val
, USER_DEFAULT_SCREEN_DPI
, get_system_dpi() );
2032 /* map value from 96 dpi to system or custom dpi */
2033 static int map_to_dpi( int val
, UINT dpi
)
2035 if (!dpi
) dpi
= get_system_dpi();
2036 return muldiv( val
, dpi
, USER_DEFAULT_SCREEN_DPI
);
2039 RECT
get_virtual_screen_rect( UINT dpi
)
2041 struct monitor
*monitor
;
2044 if (!lock_display_devices()) return rect
;
2046 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
2048 union_rect( &rect
, &rect
, &monitor
->rc_monitor
);
2051 unlock_display_devices();
2053 if (dpi
) rect
= map_dpi_rect( rect
, system_dpi
, dpi
);
2057 static BOOL
is_window_rect_full_screen( const RECT
*rect
)
2059 struct monitor
*monitor
;
2062 if (!lock_display_devices()) return FALSE
;
2064 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
2066 if (!(monitor
->dev
.state_flags
& DISPLAY_DEVICE_ACTIVE
))
2069 if (rect
->left
<= monitor
->rc_monitor
.left
&& rect
->right
>= monitor
->rc_monitor
.right
&&
2070 rect
->top
<= monitor
->rc_monitor
.top
&& rect
->bottom
>= monitor
->rc_monitor
.bottom
)
2077 unlock_display_devices();
2081 RECT
get_display_rect( const WCHAR
*display
)
2083 struct monitor
*monitor
;
2086 if (!lock_display_devices()) return rect
;
2088 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
2090 if (!monitor
->adapter
|| wcsicmp( monitor
->adapter
->dev
.device_name
, display
)) continue;
2091 rect
= monitor
->rc_monitor
;
2095 unlock_display_devices();
2096 return map_dpi_rect( rect
, system_dpi
, get_thread_dpi() );
2099 RECT
get_primary_monitor_rect( UINT dpi
)
2101 struct monitor
*monitor
;
2104 if (!lock_display_devices()) return rect
;
2106 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
2108 if (!(monitor
->flags
& MONITORINFOF_PRIMARY
)) continue;
2109 rect
= monitor
->rc_monitor
;
2113 unlock_display_devices();
2114 return map_dpi_rect( rect
, system_dpi
, dpi
);
2117 /**********************************************************************
2118 * NtUserGetDisplayConfigBufferSizes (win32u.@)
2120 LONG WINAPI
NtUserGetDisplayConfigBufferSizes( UINT32 flags
, UINT32
*num_path_info
,
2121 UINT32
*num_mode_info
)
2123 struct monitor
*monitor
;
2126 TRACE( "(0x%x %p %p)\n", flags
, num_path_info
, num_mode_info
);
2128 if (!num_path_info
|| !num_mode_info
)
2129 return ERROR_INVALID_PARAMETER
;
2136 case QDC_ONLY_ACTIVE_PATHS
:
2137 case QDC_DATABASE_CURRENT
:
2140 return ERROR_INVALID_PARAMETER
;
2143 /* FIXME: semi-stub */
2144 if (flags
!= QDC_ONLY_ACTIVE_PATHS
)
2145 FIXME( "only returning active paths\n" );
2147 if (lock_display_devices())
2149 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
2151 if (!(monitor
->dev
.state_flags
& DISPLAY_DEVICE_ACTIVE
))
2155 unlock_display_devices();
2158 *num_path_info
= count
;
2159 *num_mode_info
= count
* 2;
2160 TRACE( "returning %u paths %u modes\n", *num_path_info
, *num_mode_info
);
2161 return ERROR_SUCCESS
;
2164 /* display_lock mutex must be held */
2165 static struct display_device
*find_monitor_device( struct display_device
*adapter
, UINT index
)
2167 struct monitor
*monitor
;
2169 LIST_FOR_EACH_ENTRY(monitor
, &monitors
, struct monitor
, entry
)
2170 if (&monitor
->adapter
->dev
== adapter
&& index
== monitor
->id
)
2171 return &monitor
->dev
;
2173 WARN( "Failed to find adapter %s monitor with id %u.\n", debugstr_w(adapter
->device_name
), index
);
2177 /* display_lock mutex must be held */
2178 static struct display_device
*find_adapter_device_by_id( UINT index
)
2180 struct adapter
*adapter
;
2182 LIST_FOR_EACH_ENTRY(adapter
, &adapters
, struct adapter
, entry
)
2183 if (index
== adapter
->id
) return &adapter
->dev
;
2185 WARN( "Failed to find adapter with id %u.\n", index
);
2189 /* display_lock mutex must be held */
2190 static struct display_device
*find_adapter_device_by_name( UNICODE_STRING
*name
)
2192 SIZE_T len
= name
->Length
/ sizeof(WCHAR
);
2193 struct adapter
*adapter
;
2195 LIST_FOR_EACH_ENTRY(adapter
, &adapters
, struct adapter
, entry
)
2196 if (!wcsnicmp( name
->Buffer
, adapter
->dev
.device_name
, len
) && !adapter
->dev
.device_name
[len
])
2197 return &adapter
->dev
;
2199 WARN( "Failed to find adapter with name %s.\n", debugstr_us(name
) );
2203 /* Find and acquire the adapter matching name, or primary adapter if name is NULL.
2204 * If not NULL, the returned adapter needs to be released with adapter_release.
2206 static struct adapter
*find_adapter( UNICODE_STRING
*name
)
2208 struct display_device
*device
;
2209 struct adapter
*adapter
;
2211 if (!lock_display_devices()) return NULL
;
2213 if (name
&& name
->Length
) device
= find_adapter_device_by_name( name
);
2214 else device
= find_adapter_device_by_id( 0 ); /* use primary adapter */
2216 if (!device
) adapter
= NULL
;
2217 else adapter
= adapter_acquire( CONTAINING_RECORD( device
, struct adapter
, dev
) );
2219 unlock_display_devices();
2223 /***********************************************************************
2224 * NtUserEnumDisplayDevices (win32u.@)
2226 NTSTATUS WINAPI
NtUserEnumDisplayDevices( UNICODE_STRING
*device
, DWORD index
,
2227 DISPLAY_DEVICEW
*info
, DWORD flags
)
2229 struct display_device
*found
= NULL
;
2231 TRACE( "%s %u %p %#x\n", debugstr_us( device
), (int)index
, info
, (int)flags
);
2233 if (!info
|| !info
->cb
) return STATUS_UNSUCCESSFUL
;
2235 if (!lock_display_devices()) return STATUS_UNSUCCESSFUL
;
2237 if (!device
|| !device
->Length
) found
= find_adapter_device_by_id( index
);
2238 else if ((found
= find_adapter_device_by_name( device
))) found
= find_monitor_device( found
, index
);
2242 if (info
->cb
>= offsetof(DISPLAY_DEVICEW
, DeviceName
) + sizeof(info
->DeviceName
))
2243 lstrcpyW( info
->DeviceName
, found
->device_name
);
2244 if (info
->cb
>= offsetof(DISPLAY_DEVICEW
, DeviceString
) + sizeof(info
->DeviceString
))
2245 lstrcpyW( info
->DeviceString
, found
->device_string
);
2246 if (info
->cb
>= offsetof(DISPLAY_DEVICEW
, StateFlags
) + sizeof(info
->StateFlags
))
2247 info
->StateFlags
= found
->state_flags
;
2248 if (info
->cb
>= offsetof(DISPLAY_DEVICEW
, DeviceID
) + sizeof(info
->DeviceID
))
2249 lstrcpyW( info
->DeviceID
, (flags
& EDD_GET_DEVICE_INTERFACE_NAME
)
2250 ? found
->interface_name
: found
->device_id
);
2251 if (info
->cb
>= offsetof(DISPLAY_DEVICEW
, DeviceKey
) + sizeof(info
->DeviceKey
))
2252 lstrcpyW( info
->DeviceKey
, found
->device_key
);
2254 unlock_display_devices();
2255 return found
? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
;
2258 #define _X_FIELD(prefix, bits) \
2259 if ((fields) & prefix##_##bits) \
2261 p += sprintf( p, "%s%s", first ? "" : ",", #bits ); \
2265 static const char *_CDS_flags( DWORD fields
)
2271 _X_FIELD(CDS
, UPDATEREGISTRY
)
2273 _X_FIELD(CDS
, FULLSCREEN
)
2274 _X_FIELD(CDS
, GLOBAL
)
2275 _X_FIELD(CDS
, SET_PRIMARY
)
2276 _X_FIELD(CDS
, VIDEOPARAMETERS
)
2277 _X_FIELD(CDS
, ENABLE_UNSAFE_MODES
)
2278 _X_FIELD(CDS
, DISABLE_UNSAFE_MODES
)
2279 _X_FIELD(CDS
, RESET
)
2280 _X_FIELD(CDS
, RESET_EX
)
2281 _X_FIELD(CDS
, NORESET
)
2284 return wine_dbg_sprintf( "%s", buf
);
2287 static const char *_DM_fields( DWORD fields
)
2293 _X_FIELD(DM
, BITSPERPEL
)
2294 _X_FIELD(DM
, PELSWIDTH
)
2295 _X_FIELD(DM
, PELSHEIGHT
)
2296 _X_FIELD(DM
, DISPLAYFLAGS
)
2297 _X_FIELD(DM
, DISPLAYFREQUENCY
)
2298 _X_FIELD(DM
, POSITION
)
2299 _X_FIELD(DM
, DISPLAYORIENTATION
)
2302 return wine_dbg_sprintf( "%s", buf
);
2307 static void trace_devmode( const DEVMODEW
*devmode
)
2309 TRACE( "dmFields=%s ", _DM_fields(devmode
->dmFields
) );
2310 if (devmode
->dmFields
& DM_BITSPERPEL
)
2311 TRACE( "dmBitsPerPel=%u ", (int)devmode
->dmBitsPerPel
);
2312 if (devmode
->dmFields
& DM_PELSWIDTH
)
2313 TRACE( "dmPelsWidth=%u ", (int)devmode
->dmPelsWidth
);
2314 if (devmode
->dmFields
& DM_PELSHEIGHT
)
2315 TRACE( "dmPelsHeight=%u ", (int)devmode
->dmPelsHeight
);
2316 if (devmode
->dmFields
& DM_DISPLAYFREQUENCY
)
2317 TRACE( "dmDisplayFrequency=%u ", (int)devmode
->dmDisplayFrequency
);
2318 if (devmode
->dmFields
& DM_POSITION
)
2319 TRACE( "dmPosition=(%d,%d) ", (int)devmode
->dmPosition
.x
, (int)devmode
->dmPosition
.y
);
2320 if (devmode
->dmFields
& DM_DISPLAYFLAGS
)
2321 TRACE( "dmDisplayFlags=%#x ", (int)devmode
->dmDisplayFlags
);
2322 if (devmode
->dmFields
& DM_DISPLAYORIENTATION
)
2323 TRACE( "dmDisplayOrientation=%u ", (int)devmode
->dmDisplayOrientation
);
2327 static BOOL
is_detached_mode( const DEVMODEW
*mode
)
2329 return mode
->dmFields
& DM_POSITION
&&
2330 mode
->dmFields
& DM_PELSWIDTH
&&
2331 mode
->dmFields
& DM_PELSHEIGHT
&&
2332 mode
->dmPelsWidth
== 0 &&
2333 mode
->dmPelsHeight
== 0;
2336 static const DEVMODEW
*find_display_mode( const DEVMODEW
*modes
, DEVMODEW
*devmode
)
2338 const DEVMODEW
*mode
;
2340 if (is_detached_mode( devmode
)) return devmode
;
2342 for (mode
= modes
; mode
&& mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
2344 if ((mode
->dmFields
& DM_DISPLAYFLAGS
) && (mode
->dmDisplayFlags
& WINE_DM_UNSUPPORTED
))
2346 if ((devmode
->dmFields
& DM_BITSPERPEL
) && devmode
->dmBitsPerPel
&& devmode
->dmBitsPerPel
!= mode
->dmBitsPerPel
)
2348 if ((devmode
->dmFields
& DM_PELSWIDTH
) && devmode
->dmPelsWidth
!= mode
->dmPelsWidth
)
2350 if ((devmode
->dmFields
& DM_PELSHEIGHT
) && devmode
->dmPelsHeight
!= mode
->dmPelsHeight
)
2352 if ((devmode
->dmFields
& DM_DISPLAYFREQUENCY
) && devmode
->dmDisplayFrequency
!= mode
->dmDisplayFrequency
2353 && devmode
->dmDisplayFrequency
> 1 && mode
->dmDisplayFrequency
)
2355 if ((devmode
->dmFields
& DM_DISPLAYORIENTATION
) && devmode
->dmDisplayOrientation
!= mode
->dmDisplayOrientation
)
2357 if ((devmode
->dmFields
& DM_DISPLAYFLAGS
) && (mode
->dmFields
& DM_DISPLAYFLAGS
) &&
2358 (devmode
->dmDisplayFlags
& DM_INTERLACED
) != (mode
->dmDisplayFlags
& DM_INTERLACED
))
2360 if ((devmode
->dmFields
& DM_DISPLAYFIXEDOUTPUT
) && (mode
->dmFields
& DM_DISPLAYFIXEDOUTPUT
) &&
2361 devmode
->dmDisplayFixedOutput
!= mode
->dmDisplayFixedOutput
)
2370 static BOOL
adapter_get_full_mode( const struct adapter
*adapter
, const DEVMODEW
*devmode
, DEVMODEW
*full_mode
)
2372 const DEVMODEW
*adapter_mode
;
2376 trace_devmode( devmode
);
2378 if (devmode
->dmSize
< offsetof(DEVMODEW
, dmICMMethod
)) return FALSE
;
2379 if (!is_detached_mode( devmode
) &&
2380 (!(devmode
->dmFields
& DM_BITSPERPEL
) || !devmode
->dmBitsPerPel
) &&
2381 (!(devmode
->dmFields
& DM_PELSWIDTH
) || !devmode
->dmPelsWidth
) &&
2382 (!(devmode
->dmFields
& DM_PELSHEIGHT
) || !devmode
->dmPelsHeight
) &&
2383 (!(devmode
->dmFields
& DM_DISPLAYFREQUENCY
) || !devmode
->dmDisplayFrequency
))
2387 if (devmode
) memcpy( full_mode
, devmode
, devmode
->dmSize
);
2390 if (!adapter_get_registry_settings( adapter
, full_mode
)) return FALSE
;
2391 TRACE( "Return to original display mode\n" );
2394 if ((full_mode
->dmFields
& (DM_PELSWIDTH
| DM_PELSHEIGHT
)) != (DM_PELSWIDTH
| DM_PELSHEIGHT
))
2396 WARN( "devmode doesn't specify the resolution: %#x\n", (int)full_mode
->dmFields
);
2400 if (!is_detached_mode( full_mode
) && (!full_mode
->dmPelsWidth
|| !full_mode
->dmPelsHeight
|| !(full_mode
->dmFields
& DM_POSITION
)))
2402 DEVMODEW current_mode
= {.dmSize
= sizeof(DEVMODEW
)};
2404 if (!adapter_get_current_settings( adapter
, ¤t_mode
)) return FALSE
;
2405 if (!full_mode
->dmPelsWidth
) full_mode
->dmPelsWidth
= current_mode
.dmPelsWidth
;
2406 if (!full_mode
->dmPelsHeight
) full_mode
->dmPelsHeight
= current_mode
.dmPelsHeight
;
2407 if (!(full_mode
->dmFields
& DM_POSITION
))
2409 full_mode
->dmPosition
= current_mode
.dmPosition
;
2410 full_mode
->dmFields
|= DM_POSITION
;
2414 if ((adapter_mode
= find_display_mode( adapter
->modes
, full_mode
)) && adapter_mode
!= full_mode
)
2416 POINTL position
= full_mode
->dmPosition
;
2417 *full_mode
= *adapter_mode
;
2418 full_mode
->dmFields
|= DM_POSITION
;
2419 full_mode
->dmPosition
= position
;
2422 return adapter_mode
!= NULL
;
2425 static DEVMODEW
*get_display_settings( const WCHAR
*devname
, const DEVMODEW
*devmode
)
2427 DEVMODEW
*mode
, *displays
;
2428 struct adapter
*adapter
;
2431 /* allocate an extra mode for easier iteration */
2432 if (!(displays
= calloc( list_count( &adapters
) + 1, sizeof(DEVMODEW
) ))) return NULL
;
2435 LIST_FOR_EACH_ENTRY( adapter
, &adapters
, struct adapter
, entry
)
2437 mode
->dmSize
= sizeof(DEVMODEW
);
2438 if (devmode
&& !wcsicmp( devname
, adapter
->dev
.device_name
))
2439 memcpy( &mode
->dmFields
, &devmode
->dmFields
, devmode
->dmSize
- offsetof(DEVMODEW
, dmFields
) );
2442 if (!devname
) ret
= adapter_get_registry_settings( adapter
, mode
);
2443 else ret
= adapter_get_current_settings( adapter
, mode
);
2451 lstrcpyW( mode
->dmDeviceName
, adapter
->dev
.device_name
);
2452 mode
= NEXT_DEVMODEW(mode
);
2458 static INT
offset_length( POINT offset
)
2460 return offset
.x
* offset
.x
+ offset
.y
* offset
.y
;
2463 static void set_rect_from_devmode( RECT
*rect
, const DEVMODEW
*mode
)
2465 SetRect( rect
, mode
->dmPosition
.x
, mode
->dmPosition
.y
, mode
->dmPosition
.x
+ mode
->dmPelsWidth
,
2466 mode
->dmPosition
.y
+ mode
->dmPelsHeight
);
2469 /* Check if a rect overlaps with placed display rects */
2470 static BOOL
overlap_placed_displays( const RECT
*rect
, const DEVMODEW
*displays
)
2472 const DEVMODEW
*mode
;
2475 for (mode
= displays
; mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
2477 set_rect_from_devmode( &intersect
, mode
);
2478 if ((mode
->dmFields
& DM_POSITION
) && intersect_rect( &intersect
, &intersect
, rect
)) return TRUE
;
2484 /* Get the offset with minimum length to place a display next to the placed displays with no spacing and overlaps */
2485 static POINT
get_placement_offset( const DEVMODEW
*displays
, const DEVMODEW
*placing
)
2487 POINT points
[8], left_top
, offset
, min_offset
= {0, 0};
2488 INT point_idx
, point_count
, vertex_idx
;
2489 BOOL has_placed
= FALSE
, first
= TRUE
;
2490 RECT desired_rect
, rect
;
2491 const DEVMODEW
*mode
;
2494 set_rect_from_devmode( &desired_rect
, placing
);
2496 /* If the display to be placed is detached, no offset is needed to place it */
2497 if (IsRectEmpty( &desired_rect
)) return min_offset
;
2499 /* If there is no placed and attached display, place this display as it is */
2500 for (mode
= displays
; mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
2502 set_rect_from_devmode( &rect
, mode
);
2503 if ((mode
->dmFields
& DM_POSITION
) && !IsRectEmpty( &rect
))
2510 if (!has_placed
) return min_offset
;
2512 /* Try to place this display with each of its four vertices at every vertex of the placed
2513 * displays and see which combination has the minimum offset length */
2514 width
= desired_rect
.right
- desired_rect
.left
;
2515 height
= desired_rect
.bottom
- desired_rect
.top
;
2517 for (mode
= displays
; mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
2519 set_rect_from_devmode( &rect
, mode
);
2520 if (!(mode
->dmFields
& DM_POSITION
) || IsRectEmpty( &rect
)) continue;
2522 /* Get four vertices of the placed display rectangle */
2523 points
[0].x
= rect
.left
;
2524 points
[0].y
= rect
.top
;
2525 points
[1].x
= rect
.left
;
2526 points
[1].y
= rect
.bottom
;
2527 points
[2].x
= rect
.right
;
2528 points
[2].y
= rect
.top
;
2529 points
[3].x
= rect
.right
;
2530 points
[3].y
= rect
.bottom
;
2533 /* Intersected points when moving the display to be placed horizontally */
2534 if (desired_rect
.bottom
>= rect
.top
&& desired_rect
.top
<= rect
.bottom
)
2536 points
[point_count
].x
= rect
.left
;
2537 points
[point_count
++].y
= desired_rect
.top
;
2538 points
[point_count
].x
= rect
.right
;
2539 points
[point_count
++].y
= desired_rect
.top
;
2541 /* Intersected points when moving the display to be placed vertically */
2542 if (desired_rect
.left
<= rect
.right
&& desired_rect
.right
>= rect
.left
)
2544 points
[point_count
].x
= desired_rect
.left
;
2545 points
[point_count
++].y
= rect
.top
;
2546 points
[point_count
].x
= desired_rect
.left
;
2547 points
[point_count
++].y
= rect
.bottom
;
2550 /* Try moving each vertex of the display rectangle to each points */
2551 for (point_idx
= 0; point_idx
< point_count
; ++point_idx
)
2553 for (vertex_idx
= 0; vertex_idx
< 4; ++vertex_idx
)
2557 /* Move the bottom right vertex to the point */
2559 left_top
.x
= points
[point_idx
].x
- width
;
2560 left_top
.y
= points
[point_idx
].y
- height
;
2562 /* Move the bottom left vertex to the point */
2564 left_top
.x
= points
[point_idx
].x
;
2565 left_top
.y
= points
[point_idx
].y
- height
;
2567 /* Move the top right vertex to the point */
2569 left_top
.x
= points
[point_idx
].x
- width
;
2570 left_top
.y
= points
[point_idx
].y
;
2572 /* Move the top left vertex to the point */
2574 left_top
.x
= points
[point_idx
].x
;
2575 left_top
.y
= points
[point_idx
].y
;
2579 offset
.x
= left_top
.x
- desired_rect
.left
;
2580 offset
.y
= left_top
.y
- desired_rect
.top
;
2581 rect
= desired_rect
;
2582 OffsetRect( &rect
, offset
.x
, offset
.y
);
2583 if (!overlap_placed_displays( &rect
, displays
))
2587 min_offset
= offset
;
2592 if (offset_length( offset
) < offset_length( min_offset
)) min_offset
= offset
;
2601 static void place_all_displays( DEVMODEW
*displays
)
2603 POINT min_offset
, offset
;
2604 DEVMODEW
*mode
, *placing
;
2606 for (mode
= displays
; mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
2607 mode
->dmFields
&= ~DM_POSITION
;
2609 /* Place all displays with no extra space between them and no overlapping */
2612 /* Place the unplaced display with the minimum offset length first */
2614 for (mode
= displays
; mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
2616 if (mode
->dmFields
& DM_POSITION
) continue;
2618 offset
= get_placement_offset( displays
, mode
);
2619 if (!placing
|| offset_length( offset
) < offset_length( min_offset
))
2621 min_offset
= offset
;
2626 /* If all displays are placed */
2627 if (!placing
) break;
2629 placing
->dmPosition
.x
+= min_offset
.x
;
2630 placing
->dmPosition
.y
+= min_offset
.y
;
2631 placing
->dmFields
|= DM_POSITION
;
2635 static BOOL
all_detached_settings( const DEVMODEW
*displays
)
2637 const DEVMODEW
*mode
;
2639 for (mode
= displays
; mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
2640 if (!is_detached_mode( mode
)) return FALSE
;
2645 static LONG
apply_display_settings( const WCHAR
*devname
, const DEVMODEW
*devmode
,
2646 HWND hwnd
, DWORD flags
, void *lparam
)
2648 WCHAR primary_name
[CCHDEVICENAME
];
2649 struct display_device
*primary
;
2650 DEVMODEW
*mode
, *displays
;
2651 struct adapter
*adapter
;
2654 if (!lock_display_devices()) return DISP_CHANGE_FAILED
;
2655 if (!(displays
= get_display_settings( devname
, devmode
)))
2657 unlock_display_devices();
2658 return DISP_CHANGE_FAILED
;
2661 if (all_detached_settings( displays
))
2663 unlock_display_devices();
2664 WARN( "Detaching all modes is not permitted.\n" );
2666 return DISP_CHANGE_SUCCESSFUL
;
2669 place_all_displays( displays
);
2671 if (!(primary
= find_adapter_device_by_id( 0 ))) primary_name
[0] = 0;
2672 else wcscpy( primary_name
, primary
->device_name
);
2674 if ((ret
= user_driver
->pChangeDisplaySettings( displays
, primary_name
, hwnd
, flags
, lparam
)) == E_NOTIMPL
)
2676 /* default implementation: write current display settings to the registry. */
2678 LIST_FOR_EACH_ENTRY( adapter
, &adapters
, struct adapter
, entry
)
2680 if (!adapter_set_current_settings( adapter
, mode
))
2681 WARN( "Failed to write adapter %s current mode.\n", debugstr_w(adapter
->dev
.device_name
) );
2682 mode
= NEXT_DEVMODEW(mode
);
2684 ret
= DISP_CHANGE_SUCCESSFUL
;
2686 unlock_display_devices();
2689 if (ret
) return ret
;
2691 if (!update_display_cache( TRUE
))
2692 WARN( "Failed to update display cache after mode change.\n" );
2694 if ((adapter
= find_adapter( NULL
)))
2696 DEVMODEW current_mode
= {.dmSize
= sizeof(DEVMODEW
)};
2698 if (!adapter_get_current_settings( adapter
, ¤t_mode
)) WARN( "Failed to get primary adapter current display settings.\n" );
2699 adapter_release( adapter
);
2701 send_notify_message( NtUserGetDesktopWindow(), WM_DISPLAYCHANGE
, current_mode
.dmBitsPerPel
,
2702 MAKELPARAM( current_mode
.dmPelsWidth
, current_mode
.dmPelsHeight
), FALSE
);
2703 send_message_timeout( HWND_BROADCAST
, WM_DISPLAYCHANGE
, current_mode
.dmBitsPerPel
,
2704 MAKELPARAM( current_mode
.dmPelsWidth
, current_mode
.dmPelsHeight
),
2705 SMTO_ABORTIFHUNG
, 2000, FALSE
);
2711 /***********************************************************************
2712 * NtUserChangeDisplaySettings (win32u.@)
2714 LONG WINAPI
NtUserChangeDisplaySettings( UNICODE_STRING
*devname
, DEVMODEW
*devmode
, HWND hwnd
,
2715 DWORD flags
, void *lparam
)
2717 DEVMODEW full_mode
= {.dmSize
= sizeof(DEVMODEW
)};
2718 int ret
= DISP_CHANGE_SUCCESSFUL
;
2719 struct adapter
*adapter
;
2721 TRACE( "%s %p %p %#x %p\n", debugstr_us(devname
), devmode
, hwnd
, (int)flags
, lparam
);
2722 TRACE( "flags=%s\n", _CDS_flags(flags
) );
2724 if ((!devname
|| !devname
->Length
) && !devmode
) return apply_display_settings( NULL
, NULL
, hwnd
, flags
, lparam
);
2726 if (!(adapter
= find_adapter( devname
))) return DISP_CHANGE_BADPARAM
;
2728 if (!adapter_get_full_mode( adapter
, devmode
, &full_mode
)) ret
= DISP_CHANGE_BADMODE
;
2729 else if ((flags
& CDS_UPDATEREGISTRY
) && !adapter_set_registry_settings( adapter
, &full_mode
)) ret
= DISP_CHANGE_NOTUPDATED
;
2730 else if (flags
& (CDS_TEST
| CDS_NORESET
)) ret
= DISP_CHANGE_SUCCESSFUL
;
2731 else ret
= apply_display_settings( adapter
->dev
.device_name
, &full_mode
, hwnd
, flags
, lparam
);
2732 adapter_release( adapter
);
2734 if (ret
) ERR( "Changing %s display settings returned %d.\n", debugstr_us(devname
), ret
);
2738 static BOOL
adapter_enum_display_settings( const struct adapter
*adapter
, UINT index
, DEVMODEW
*devmode
, UINT flags
)
2740 DEVMODEW current_mode
= {.dmSize
= sizeof(DEVMODEW
)};
2741 const DEVMODEW
*adapter_mode
;
2743 if (!(flags
& EDS_ROTATEDMODE
) && !adapter_get_current_settings( adapter
, ¤t_mode
))
2745 WARN( "Failed to query current display mode for EDS_ROTATEDMODE flag.\n" );
2749 for (adapter_mode
= adapter
->modes
; adapter_mode
->dmSize
; adapter_mode
= NEXT_DEVMODEW(adapter_mode
))
2751 if (!(flags
& EDS_ROTATEDMODE
) && (adapter_mode
->dmFields
& DM_DISPLAYORIENTATION
) &&
2752 adapter_mode
->dmDisplayOrientation
!= current_mode
.dmDisplayOrientation
)
2754 if (!(flags
& EDS_RAWMODE
) && (adapter_mode
->dmFields
& DM_DISPLAYFLAGS
) &&
2755 (adapter_mode
->dmDisplayFlags
& WINE_DM_UNSUPPORTED
))
2759 memcpy( &devmode
->dmFields
, &adapter_mode
->dmFields
, devmode
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmFields
) );
2760 devmode
->dmDisplayFlags
&= ~WINE_DM_UNSUPPORTED
;
2765 WARN( "device %s, index %#x, flags %#x display mode not found.\n",
2766 debugstr_w( adapter
->dev
.device_name
), index
, flags
);
2767 RtlSetLastWin32Error( ERROR_NO_MORE_FILES
);
2771 /***********************************************************************
2772 * NtUserEnumDisplaySettings (win32u.@)
2774 BOOL WINAPI
NtUserEnumDisplaySettings( UNICODE_STRING
*device
, DWORD index
, DEVMODEW
*devmode
, DWORD flags
)
2776 static const WCHAR wine_display_driverW
[] = {'W','i','n','e',' ','D','i','s','p','l','a','y',' ','D','r','i','v','e','r',0};
2777 struct adapter
*adapter
;
2780 TRACE( "device %s, index %#x, devmode %p, flags %#x\n",
2781 debugstr_us(device
), (int)index
, devmode
, (int)flags
);
2783 if (!(adapter
= find_adapter( device
))) return FALSE
;
2785 lstrcpynW( devmode
->dmDeviceName
, wine_display_driverW
, ARRAY_SIZE(devmode
->dmDeviceName
) );
2786 devmode
->dmSpecVersion
= DM_SPECVERSION
;
2787 devmode
->dmDriverVersion
= DM_SPECVERSION
;
2788 devmode
->dmSize
= offsetof(DEVMODEW
, dmICMMethod
);
2789 devmode
->dmDriverExtra
= 0;
2791 if (index
== ENUM_REGISTRY_SETTINGS
) ret
= adapter_get_registry_settings( adapter
, devmode
);
2792 else if (index
== ENUM_CURRENT_SETTINGS
) ret
= adapter_get_current_settings( adapter
, devmode
);
2793 else ret
= adapter_enum_display_settings( adapter
, index
, devmode
, flags
);
2794 adapter_release( adapter
);
2796 if (!ret
) WARN( "Failed to query %s display settings.\n", debugstr_us(device
) );
2797 else TRACE( "position %dx%d, resolution %ux%u, frequency %u, depth %u, orientation %#x.\n",
2798 (int)devmode
->dmPosition
.x
, (int)devmode
->dmPosition
.y
, (int)devmode
->dmPelsWidth
,
2799 (int)devmode
->dmPelsHeight
, (int)devmode
->dmDisplayFrequency
,
2800 (int)devmode
->dmBitsPerPel
, (int)devmode
->dmDisplayOrientation
);
2804 struct monitor_enum_info
2810 static unsigned int active_monitor_count(void)
2812 struct monitor
*monitor
;
2813 unsigned int count
= 0;
2815 LIST_FOR_EACH_ENTRY(monitor
, &monitors
, struct monitor
, entry
)
2817 if ((monitor
->dev
.state_flags
& DISPLAY_DEVICE_ACTIVE
)) count
++;
2822 INT
get_display_depth( UNICODE_STRING
*name
)
2824 struct display_device
*device
;
2828 if (!lock_display_devices())
2831 if (name
&& name
->Length
)
2832 device
= find_adapter_device_by_name( name
);
2834 device
= find_adapter_device_by_id( 0 ); /* use primary adapter */
2838 unlock_display_devices();
2842 is_primary
= !!(device
->state_flags
& DISPLAY_DEVICE_PRIMARY_DEVICE
);
2843 if ((depth
= user_driver
->pGetDisplayDepth( device
->device_name
, is_primary
)) < 0)
2845 struct adapter
*adapter
= CONTAINING_RECORD( device
, struct adapter
, dev
);
2846 DEVMODEW current_mode
= {.dmSize
= sizeof(DEVMODEW
)};
2848 if (!adapter_get_current_settings( adapter
, ¤t_mode
)) depth
= 32;
2849 else depth
= current_mode
.dmBitsPerPel
;
2852 unlock_display_devices();
2856 /***********************************************************************
2857 * NtUserEnumDisplayMonitors (win32u.@)
2859 BOOL WINAPI
NtUserEnumDisplayMonitors( HDC hdc
, RECT
*rect
, MONITORENUMPROC proc
, LPARAM lparam
)
2861 struct monitor_enum_info enum_buf
[8], *enum_info
= enum_buf
;
2862 struct enum_display_monitor_params params
;
2863 struct monitor
*monitor
;
2864 unsigned int count
= 0, i
;
2872 if (!(dc
= get_dc_ptr( hdc
))) return FALSE
;
2873 origin
.x
= dc
->attr
->vis_rect
.left
;
2874 origin
.y
= dc
->attr
->vis_rect
.top
;
2875 release_dc_ptr( dc
);
2876 if (NtGdiGetAppClipBox( hdc
, &limit
) == ERROR
) return FALSE
;
2880 origin
.x
= origin
.y
= 0;
2881 limit
.left
= limit
.top
= INT_MIN
;
2882 limit
.right
= limit
.bottom
= INT_MAX
;
2884 if (rect
&& !intersect_rect( &limit
, &limit
, rect
)) return TRUE
;
2886 if (!lock_display_devices()) return FALSE
;
2888 count
= list_count( &monitors
);
2889 if (!count
|| (count
> ARRAYSIZE(enum_buf
) &&
2890 !(enum_info
= malloc( count
* sizeof(*enum_info
) ))))
2892 unlock_display_devices();
2897 LIST_FOR_EACH_ENTRY(monitor
, &monitors
, struct monitor
, entry
)
2901 if (!(monitor
->dev
.state_flags
& DISPLAY_DEVICE_ACTIVE
)) continue;
2903 monrect
= map_dpi_rect( monitor
->rc_monitor
, get_monitor_dpi( monitor
->handle
),
2905 OffsetRect( &monrect
, -origin
.x
, -origin
.y
);
2906 if (!intersect_rect( &monrect
, &monrect
, &limit
)) continue;
2907 if (monitor
->is_clone
) continue;
2909 enum_info
[count
].handle
= monitor
->handle
;
2910 enum_info
[count
].rect
= monrect
;
2914 unlock_display_devices();
2918 params
.lparam
= lparam
;
2919 for (i
= 0; i
< count
; i
++)
2923 params
.monitor
= enum_info
[i
].handle
;
2924 params
.rect
= enum_info
[i
].rect
;
2925 if (!KeUserModeCallback( NtUserCallEnumDisplayMonitor
, ¶ms
, sizeof(params
),
2926 &ret_ptr
, &ret_len
))
2932 if (enum_info
!= enum_buf
) free( enum_info
);
2936 BOOL
get_monitor_info( HMONITOR handle
, MONITORINFO
*info
)
2938 struct monitor
*monitor
;
2939 UINT dpi_from
, dpi_to
;
2941 if (info
->cbSize
!= sizeof(MONITORINFOEXW
) && info
->cbSize
!= sizeof(MONITORINFO
)) return FALSE
;
2943 if (!lock_display_devices()) return FALSE
;
2945 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
2947 if (monitor
->handle
!= handle
) continue;
2948 if (!(monitor
->dev
.state_flags
& DISPLAY_DEVICE_ACTIVE
)) break;
2950 /* FIXME: map dpi */
2951 info
->rcMonitor
= monitor
->rc_monitor
;
2952 info
->rcWork
= monitor
->rc_work
;
2953 info
->dwFlags
= monitor
->flags
;
2954 if (info
->cbSize
>= sizeof(MONITORINFOEXW
))
2956 if (monitor
->adapter
)
2957 lstrcpyW( ((MONITORINFOEXW
*)info
)->szDevice
, monitor
->adapter
->dev
.device_name
);
2959 asciiz_to_unicode( ((MONITORINFOEXW
*)info
)->szDevice
, "WinDisc" );
2961 unlock_display_devices();
2963 if ((dpi_to
= get_thread_dpi()))
2965 dpi_from
= get_monitor_dpi( handle
);
2966 info
->rcMonitor
= map_dpi_rect( info
->rcMonitor
, dpi_from
, dpi_to
);
2967 info
->rcWork
= map_dpi_rect( info
->rcWork
, dpi_from
, dpi_to
);
2969 TRACE( "flags %04x, monitor %s, work %s\n", (int)info
->dwFlags
,
2970 wine_dbgstr_rect(&info
->rcMonitor
), wine_dbgstr_rect(&info
->rcWork
));
2974 unlock_display_devices();
2975 WARN( "invalid handle %p\n", handle
);
2976 RtlSetLastWin32Error( ERROR_INVALID_MONITOR_HANDLE
);
2980 HMONITOR
monitor_from_rect( const RECT
*rect
, UINT flags
, UINT dpi
)
2982 HMONITOR primary
= 0, nearest
= 0, ret
= 0;
2983 UINT max_area
= 0, min_distance
= ~0u;
2984 struct monitor
*monitor
;
2987 r
= map_dpi_rect( *rect
, dpi
, system_dpi
);
2988 if (IsRectEmpty( &r
))
2990 r
.right
= r
.left
+ 1;
2991 r
.bottom
= r
.top
+ 1;
2994 if (!lock_display_devices()) return 0;
2996 LIST_FOR_EACH_ENTRY(monitor
, &monitors
, struct monitor
, entry
)
2999 RECT monitor_rect
= map_dpi_rect( monitor
->rc_monitor
, get_monitor_dpi( monitor
->handle
),
3002 if (intersect_rect( &intersect
, &monitor_rect
, &r
))
3004 /* check for larger intersecting area */
3005 UINT area
= (intersect
.right
- intersect
.left
) * (intersect
.bottom
- intersect
.top
);
3006 if (area
> max_area
)
3009 ret
= monitor
->handle
;
3012 else if (!max_area
) /* if not intersecting, check for min distance */
3017 if (r
.right
<= monitor_rect
.left
) x
= monitor_rect
.left
- r
.right
;
3018 else if (monitor_rect
.right
<= r
.left
) x
= r
.left
- monitor_rect
.right
;
3020 if (r
.bottom
<= monitor_rect
.top
) y
= monitor_rect
.top
- r
.bottom
;
3021 else if (monitor_rect
.bottom
<= r
.top
) y
= r
.top
- monitor_rect
.bottom
;
3023 distance
= x
* x
+ y
* y
;
3024 if (distance
< min_distance
)
3026 min_distance
= distance
;
3027 nearest
= monitor
->handle
;
3031 if (monitor
->flags
& MONITORINFOF_PRIMARY
) primary
= monitor
->handle
;
3034 unlock_display_devices();
3038 if (flags
& MONITOR_DEFAULTTOPRIMARY
) ret
= primary
;
3039 else if (flags
& MONITOR_DEFAULTTONEAREST
) ret
= nearest
;
3042 TRACE( "%s flags %x returning %p\n", wine_dbgstr_rect(rect
), flags
, ret
);
3046 HMONITOR
monitor_from_point( POINT pt
, UINT flags
, UINT dpi
)
3049 SetRect( &rect
, pt
.x
, pt
.y
, pt
.x
+ 1, pt
.y
+ 1 );
3050 return monitor_from_rect( &rect
, flags
, dpi
);
3053 /* see MonitorFromWindow */
3054 HMONITOR
monitor_from_window( HWND hwnd
, UINT flags
, UINT dpi
)
3059 TRACE( "(%p, 0x%08x)\n", hwnd
, flags
);
3061 wp
.length
= sizeof(wp
);
3062 if (is_iconic( hwnd
) && NtUserGetWindowPlacement( hwnd
, &wp
))
3063 return monitor_from_rect( &wp
.rcNormalPosition
, flags
, dpi
);
3065 if (get_window_rect( hwnd
, &rect
, dpi
))
3066 return monitor_from_rect( &rect
, flags
, dpi
);
3068 if (!(flags
& (MONITOR_DEFAULTTOPRIMARY
|MONITOR_DEFAULTTONEAREST
))) return 0;
3069 /* retrieve the primary */
3070 SetRect( &rect
, 0, 0, 1, 1 );
3071 return monitor_from_rect( &rect
, flags
, dpi
);
3074 /***********************************************************************
3075 * NtUserGetSystemDpiForProcess (win32u.@)
3077 ULONG WINAPI
NtUserGetSystemDpiForProcess( HANDLE process
)
3079 if (process
&& process
!= GetCurrentProcess())
3081 FIXME( "not supported on other process %p\n", process
);
3088 /***********************************************************************
3089 * NtUserGetDpiForMonitor (win32u.@)
3091 BOOL WINAPI
NtUserGetDpiForMonitor( HMONITOR monitor
, UINT type
, UINT
*x
, UINT
*y
)
3095 RtlSetLastWin32Error( ERROR_BAD_ARGUMENTS
);
3100 RtlSetLastWin32Error( ERROR_INVALID_ADDRESS
);
3103 switch (get_thread_dpi_awareness())
3105 case DPI_AWARENESS_UNAWARE
: *x
= *y
= USER_DEFAULT_SCREEN_DPI
; break;
3106 case DPI_AWARENESS_SYSTEM_AWARE
: *x
= *y
= system_dpi
; break;
3107 default: *x
= *y
= get_monitor_dpi( monitor
); break;
3112 /**********************************************************************
3113 * LogicalToPhysicalPointForPerMonitorDPI (win32u.@)
3115 BOOL WINAPI
NtUserLogicalToPerMonitorDPIPhysicalPoint( HWND hwnd
, POINT
*pt
)
3119 if (!get_window_rect( hwnd
, &rect
, get_thread_dpi() )) return FALSE
;
3120 if (pt
->x
< rect
.left
|| pt
->y
< rect
.top
|| pt
->x
> rect
.right
|| pt
->y
> rect
.bottom
) return FALSE
;
3121 *pt
= point_win_to_phys_dpi( hwnd
, *pt
);
3125 /**********************************************************************
3126 * NtUserPerMonitorDPIPhysicalToLogicalPoint (win32u.@)
3128 BOOL WINAPI
NtUserPerMonitorDPIPhysicalToLogicalPoint( HWND hwnd
, POINT
*pt
)
3133 if (get_window_rect( hwnd
, &rect
, 0 ) &&
3134 pt
->x
>= rect
.left
&& pt
->y
>= rect
.top
&& pt
->x
<= rect
.right
&& pt
->y
<= rect
.bottom
)
3136 *pt
= point_phys_to_win_dpi( hwnd
, *pt
);
3142 /* retrieve the cached base keys for a given entry */
3143 static BOOL
get_base_keys( enum parameter_key index
, HKEY
*base_key
, HKEY
*volatile_key
)
3145 static HKEY base_keys
[NB_PARAM_KEYS
];
3146 static HKEY volatile_keys
[NB_PARAM_KEYS
];
3150 if (!base_keys
[index
] && base_key
)
3152 if (!(key
= reg_create_key( hkcu_key
, bufferW
,
3153 asciiz_to_unicode( bufferW
, parameter_key_names
[index
] ) - sizeof(WCHAR
),
3156 if (InterlockedCompareExchangePointer( (void **)&base_keys
[index
], key
, 0 ))
3159 if (!volatile_keys
[index
] && volatile_key
)
3161 if (!(key
= reg_create_key( volatile_base_key
, bufferW
,
3162 asciiz_to_unicode( bufferW
, parameter_key_names
[index
] ) - sizeof(WCHAR
),
3163 REG_OPTION_VOLATILE
, NULL
)))
3165 if (InterlockedCompareExchangePointer( (void **)&volatile_keys
[index
], key
, 0 ))
3168 if (base_key
) *base_key
= base_keys
[index
];
3169 if (volatile_key
) *volatile_key
= volatile_keys
[index
];
3173 /* load a value to a registry entry */
3174 static DWORD
load_entry( struct sysparam_entry
*entry
, void *data
, DWORD size
)
3177 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
3179 HKEY base_key
, volatile_key
;
3181 if (!get_base_keys( entry
->base_key
, &base_key
, &volatile_key
)) return FALSE
;
3183 if (!(count
= query_reg_ascii_value( volatile_key
, entry
->regval
, value
, sizeof(buffer
) )))
3184 count
= query_reg_ascii_value( base_key
, entry
->regval
, value
, sizeof(buffer
) );
3188 /* make sure strings are null-terminated */
3189 if (value
->Type
== REG_SZ
) ((WCHAR
*)value
->Data
)[count
/ sizeof(WCHAR
) - 1] = 0;
3191 if (count
) memcpy( data
, value
->Data
, count
);
3192 entry
->loaded
= TRUE
;
3196 /* save a value to a registry entry */
3197 static BOOL
save_entry( const struct sysparam_entry
*entry
, const void *data
, DWORD size
,
3198 DWORD type
, UINT flags
)
3200 HKEY base_key
, volatile_key
;
3203 asciiz_to_unicode( nameW
, entry
->regval
);
3204 if (flags
& SPIF_UPDATEINIFILE
)
3206 if (!get_base_keys( entry
->base_key
, &base_key
, &volatile_key
)) return FALSE
;
3207 if (!set_reg_value( base_key
, nameW
, type
, data
, size
)) return FALSE
;
3208 reg_delete_value( volatile_key
, nameW
);
3210 if (entry
->mirror
&& get_base_keys( entry
->mirror_key
, &base_key
, NULL
))
3212 asciiz_to_unicode( nameW
, entry
->mirror
);
3213 set_reg_value( base_key
, nameW
, type
, data
, size
);
3218 if (!get_base_keys( entry
->base_key
, NULL
, &volatile_key
)) return FALSE
;
3219 if (!set_reg_value( volatile_key
, nameW
, type
, data
, size
)) return FALSE
;
3224 /* save a string value to a registry entry */
3225 static BOOL
save_entry_string( const struct sysparam_entry
*entry
, const WCHAR
*str
, UINT flags
)
3227 return save_entry( entry
, str
, (lstrlenW(str
) + 1) * sizeof(WCHAR
), REG_SZ
, flags
);
3230 /* initialize an entry in the registry if missing */
3231 static BOOL
init_entry( struct sysparam_entry
*entry
, const void *data
, DWORD size
, DWORD type
)
3233 KEY_VALUE_PARTIAL_INFORMATION value
;
3234 UNICODE_STRING name
;
3240 if (!get_base_keys( entry
->base_key
, &base_key
, NULL
)) return FALSE
;
3242 name
.Buffer
= nameW
;
3243 name
.MaximumLength
= asciiz_to_unicode( nameW
, entry
->regval
);
3244 name
.Length
= name
.MaximumLength
- sizeof(WCHAR
);
3245 status
= NtQueryValueKey( base_key
, &name
, KeyValuePartialInformation
,
3246 &value
, sizeof(value
), &count
);
3247 if (!status
|| status
== STATUS_BUFFER_OVERFLOW
) return TRUE
;
3249 if (!set_reg_value( base_key
, nameW
, type
, data
, size
)) return FALSE
;
3250 if (entry
->mirror
&& get_base_keys( entry
->mirror_key
, &base_key
, NULL
))
3252 asciiz_to_unicode( nameW
, entry
->mirror
);
3253 set_reg_value( base_key
, nameW
, type
, data
, size
);
3255 entry
->loaded
= TRUE
;
3259 /* initialize a string value in the registry if missing */
3260 static BOOL
init_entry_string( struct sysparam_entry
*entry
, const WCHAR
*str
)
3262 return init_entry( entry
, str
, (lstrlenW(str
) + 1) * sizeof(WCHAR
), REG_SZ
);
3265 /* set an int parameter in the registry */
3266 static BOOL
set_int_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3271 sprintf( buf
, "%d", int_param
);
3272 asciiz_to_unicode( bufW
, buf
);
3273 if (!save_entry_string( &entry
->hdr
, bufW
, flags
)) return FALSE
;
3274 entry
->uint
.val
= int_param
;
3275 entry
->hdr
.loaded
= TRUE
;
3279 /* initialize an int parameter */
3280 static BOOL
init_int_entry( union sysparam_all_entry
*entry
)
3285 sprintf( buf
, "%d", entry
->uint
.val
);
3286 asciiz_to_unicode( bufW
, buf
);
3287 return init_entry_string( &entry
->hdr
, bufW
);
3290 /* load a uint parameter from the registry */
3291 static BOOL
get_uint_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3293 if (!ptr_param
) return FALSE
;
3295 if (!entry
->hdr
.loaded
)
3298 if (load_entry( &entry
->hdr
, buf
, sizeof(buf
) )) entry
->uint
.val
= wcstol( buf
, NULL
, 10 );
3300 *(UINT
*)ptr_param
= entry
->uint
.val
;
3304 /* set a uint parameter in the registry */
3305 static BOOL
set_uint_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3310 sprintf( buf
, "%u", int_param
);
3311 asciiz_to_unicode( bufW
, buf
);
3312 if (!save_entry_string( &entry
->hdr
, bufW
, flags
)) return FALSE
;
3313 entry
->uint
.val
= int_param
;
3314 entry
->hdr
.loaded
= TRUE
;
3318 /* initialize a uint parameter */
3319 static BOOL
init_uint_entry( union sysparam_all_entry
*entry
)
3324 sprintf( buf
, "%u", entry
->uint
.val
);
3325 asciiz_to_unicode( bufW
, buf
);
3326 return init_entry_string( &entry
->hdr
, bufW
);
3329 /* load a twips parameter from the registry */
3330 static BOOL
get_twips_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3334 if (!ptr_param
) return FALSE
;
3336 if (!entry
->hdr
.loaded
)
3339 if (load_entry( &entry
->hdr
, buf
, sizeof(buf
) )) entry
->uint
.val
= wcstol( buf
, NULL
, 10 );
3342 /* Dimensions are quoted as being "twips" values if negative and pixels if positive.
3343 * One inch is 1440 twips.
3345 * Technical Reference to the Windows 2000 Registry ->
3346 * HKEY_CURRENT_USER -> Control Panel -> Desktop -> WindowMetrics
3348 val
= entry
->uint
.val
;
3350 val
= muldiv( -val
, dpi
, 1440 );
3352 val
= map_to_dpi( val
, dpi
);
3354 *(int *)ptr_param
= val
;
3358 /* set a twips parameter in the registry */
3359 static BOOL
set_twips_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3361 int val
= int_param
;
3362 if (val
> 0) val
= map_from_system_dpi( val
);
3363 return set_int_entry( entry
, val
, ptr_param
, flags
);
3366 /* load a bool parameter from the registry */
3367 static BOOL
get_bool_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3369 if (!ptr_param
) return FALSE
;
3371 if (!entry
->hdr
.loaded
)
3374 if (load_entry( &entry
->hdr
, buf
, sizeof(buf
) )) entry
->bool.val
= wcstol( buf
, NULL
, 10 ) != 0;
3376 *(UINT
*)ptr_param
= entry
->bool.val
;
3380 /* set a bool parameter in the registry */
3381 static BOOL
set_bool_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3383 WCHAR buf
[] = { int_param
? '1' : '0', 0 };
3385 if (!save_entry_string( &entry
->hdr
, buf
, flags
)) return FALSE
;
3386 entry
->bool.val
= int_param
!= 0;
3387 entry
->hdr
.loaded
= TRUE
;
3391 /* initialize a bool parameter */
3392 static BOOL
init_bool_entry( union sysparam_all_entry
*entry
)
3394 WCHAR buf
[] = { entry
->bool.val
? '1' : '0', 0 };
3396 return init_entry_string( &entry
->hdr
, buf
);
3399 /* load a bool parameter using Yes/No strings from the registry */
3400 static BOOL
get_yesno_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3402 if (!ptr_param
) return FALSE
;
3404 if (!entry
->hdr
.loaded
)
3407 if (load_entry( &entry
->hdr
, buf
, sizeof(buf
) )) entry
->bool.val
= !wcsicmp( yesW
, buf
);
3409 *(UINT
*)ptr_param
= entry
->bool.val
;
3413 /* set a bool parameter using Yes/No strings from the registry */
3414 static BOOL
set_yesno_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3416 const WCHAR
*str
= int_param
? yesW
: noW
;
3418 if (!save_entry_string( &entry
->hdr
, str
, flags
)) return FALSE
;
3419 entry
->bool.val
= int_param
!= 0;
3420 entry
->hdr
.loaded
= TRUE
;
3424 /* initialize a bool parameter using Yes/No strings */
3425 static BOOL
init_yesno_entry( union sysparam_all_entry
*entry
)
3427 return init_entry_string( &entry
->hdr
, entry
->bool.val
? yesW
: noW
);
3430 /* load a dword (binary) parameter from the registry */
3431 static BOOL
get_dword_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3433 if (!ptr_param
) return FALSE
;
3435 if (!entry
->hdr
.loaded
)
3438 if (load_entry( &entry
->hdr
, &val
, sizeof(val
) ) == sizeof(DWORD
)) entry
->dword
.val
= val
;
3440 *(DWORD
*)ptr_param
= entry
->dword
.val
;
3444 /* set a dword (binary) parameter in the registry */
3445 static BOOL
set_dword_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3447 DWORD val
= PtrToUlong( ptr_param
);
3449 if (!save_entry( &entry
->hdr
, &val
, sizeof(val
), REG_DWORD
, flags
)) return FALSE
;
3450 entry
->dword
.val
= val
;
3451 entry
->hdr
.loaded
= TRUE
;
3455 /* initialize a dword parameter */
3456 static BOOL
init_dword_entry( union sysparam_all_entry
*entry
)
3458 return init_entry( &entry
->hdr
, &entry
->dword
.val
, sizeof(entry
->dword
.val
), REG_DWORD
);
3461 /* load an RGB parameter from the registry */
3462 static BOOL
get_rgb_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3464 if (!ptr_param
) return FALSE
;
3466 if (!entry
->hdr
.loaded
)
3470 if (load_entry( &entry
->hdr
, buf
, sizeof(buf
) ))
3473 WCHAR
*end
, *str
= buf
;
3475 r
= wcstoul( str
, &end
, 10 );
3476 if (end
== str
|| !*end
) goto done
;
3478 g
= wcstoul( str
, &end
, 10 );
3479 if (end
== str
|| !*end
) goto done
;
3481 b
= wcstoul( str
, &end
, 10 );
3482 if (end
== str
) goto done
;
3483 if (r
> 255 || g
> 255 || b
> 255) goto done
;
3484 entry
->rgb
.val
= RGB( r
, g
, b
);
3488 *(COLORREF
*)ptr_param
= entry
->rgb
.val
;
3492 /* set an RGB parameter in the registry */
3493 static BOOL
set_rgb_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3500 sprintf( buf
, "%u %u %u", GetRValue(int_param
), GetGValue(int_param
), GetBValue(int_param
) );
3501 asciiz_to_unicode( bufW
, buf
);
3502 if (!save_entry_string( &entry
->hdr
, bufW
, flags
)) return FALSE
;
3503 entry
->rgb
.val
= int_param
;
3504 entry
->hdr
.loaded
= TRUE
;
3505 if ((brush
= InterlockedExchangePointer( (void **)&entry
->rgb
.brush
, 0 )))
3507 make_gdi_object_system( brush
, FALSE
);
3508 NtGdiDeleteObjectApp( brush
);
3510 if ((pen
= InterlockedExchangePointer( (void **)&entry
->rgb
.pen
, 0 )))
3512 make_gdi_object_system( pen
, FALSE
);
3513 NtGdiDeleteObjectApp( pen
);
3518 /* initialize an RGB parameter */
3519 static BOOL
init_rgb_entry( union sysparam_all_entry
*entry
)
3524 sprintf( buf
, "%u %u %u", GetRValue(entry
->rgb
.val
), GetGValue(entry
->rgb
.val
),
3525 GetBValue(entry
->rgb
.val
) );
3526 asciiz_to_unicode( bufW
, buf
);
3527 return init_entry_string( &entry
->hdr
, bufW
);
3530 /* get a path parameter in the registry */
3531 static BOOL
get_path_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3533 if (!ptr_param
) return FALSE
;
3535 if (!entry
->hdr
.loaded
)
3537 WCHAR buffer
[MAX_PATH
];
3539 if (load_entry( &entry
->hdr
, buffer
, sizeof(buffer
) ))
3540 lstrcpynW( entry
->path
.path
, buffer
, MAX_PATH
);
3542 lstrcpynW( ptr_param
, entry
->path
.path
, int_param
);
3546 /* set a path parameter in the registry */
3547 static BOOL
set_path_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3549 WCHAR buffer
[MAX_PATH
];
3552 lstrcpynW( buffer
, ptr_param
, MAX_PATH
);
3553 ret
= save_entry_string( &entry
->hdr
, buffer
, flags
);
3556 lstrcpyW( entry
->path
.path
, buffer
);
3557 entry
->hdr
.loaded
= TRUE
;
3562 /* initialize a path parameter */
3563 static BOOL
init_path_entry( union sysparam_all_entry
*entry
)
3565 return init_entry_string( &entry
->hdr
, entry
->path
.path
);
3568 /* get a binary parameter in the registry */
3569 static BOOL
get_binary_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3571 if (!ptr_param
) return FALSE
;
3573 if (!entry
->hdr
.loaded
)
3575 void *buffer
= malloc( entry
->bin
.size
);
3576 DWORD len
= load_entry( &entry
->hdr
, buffer
, entry
->bin
.size
);
3580 memcpy( entry
->bin
.ptr
, buffer
, entry
->bin
.size
);
3581 memset( (char *)entry
->bin
.ptr
+ len
, 0, entry
->bin
.size
- len
);
3585 memcpy( ptr_param
, entry
->bin
.ptr
, min( int_param
, entry
->bin
.size
) );
3589 /* set a binary parameter in the registry */
3590 static BOOL
set_binary_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3593 void *buffer
= malloc( entry
->bin
.size
);
3595 memcpy( buffer
, entry
->bin
.ptr
, entry
->bin
.size
);
3596 memcpy( buffer
, ptr_param
, min( int_param
, entry
->bin
.size
));
3597 ret
= save_entry( &entry
->hdr
, buffer
, entry
->bin
.size
, REG_BINARY
, flags
);
3600 memcpy( entry
->bin
.ptr
, buffer
, entry
->bin
.size
);
3601 entry
->hdr
.loaded
= TRUE
;
3607 /* initialize a binary parameter */
3608 static BOOL
init_binary_entry( union sysparam_all_entry
*entry
)
3610 return init_entry( &entry
->hdr
, entry
->bin
.ptr
, entry
->bin
.size
, REG_BINARY
);
3613 static void logfont16to32( const LOGFONT16
*font16
, LPLOGFONTW font32
)
3615 font32
->lfHeight
= font16
->lfHeight
;
3616 font32
->lfWidth
= font16
->lfWidth
;
3617 font32
->lfEscapement
= font16
->lfEscapement
;
3618 font32
->lfOrientation
= font16
->lfOrientation
;
3619 font32
->lfWeight
= font16
->lfWeight
;
3620 font32
->lfItalic
= font16
->lfItalic
;
3621 font32
->lfUnderline
= font16
->lfUnderline
;
3622 font32
->lfStrikeOut
= font16
->lfStrikeOut
;
3623 font32
->lfCharSet
= font16
->lfCharSet
;
3624 font32
->lfOutPrecision
= font16
->lfOutPrecision
;
3625 font32
->lfClipPrecision
= font16
->lfClipPrecision
;
3626 font32
->lfQuality
= font16
->lfQuality
;
3627 font32
->lfPitchAndFamily
= font16
->lfPitchAndFamily
;
3628 win32u_mbtowc( &ansi_cp
, font32
->lfFaceName
, LF_FACESIZE
, font16
->lfFaceName
,
3629 strlen( font16
->lfFaceName
));
3630 font32
->lfFaceName
[LF_FACESIZE
-1] = 0;
3633 static void get_real_fontname( LOGFONTW
*lf
, WCHAR fullname
[LF_FACESIZE
] )
3635 struct font_enum_entry enum_entry
;
3636 ULONG count
= sizeof(enum_entry
);
3639 hdc
= get_display_dc();
3640 NtGdiEnumFonts( hdc
, 0, 0, lstrlenW( lf
->lfFaceName
), lf
->lfFaceName
, lf
->lfCharSet
,
3641 &count
, &enum_entry
);
3642 release_display_dc( hdc
);
3645 lstrcpyW( fullname
, enum_entry
.lf
.elfFullName
);
3647 lstrcpyW( fullname
, lf
->lfFaceName
);
3650 LONG
get_char_dimensions( HDC hdc
, TEXTMETRICW
*metric
, int *height
)
3653 static const WCHAR abcdW
[] =
3654 {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3655 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3656 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
3658 if (metric
&& !NtGdiGetTextMetricsW( hdc
, metric
, 0 )) return 0;
3660 if (!NtGdiGetTextExtentExW( hdc
, abcdW
, ARRAYSIZE(abcdW
), 0, NULL
, NULL
, &sz
, 0 ))
3663 if (height
) *height
= sz
.cy
;
3664 return (sz
.cx
/ 26 + 1) / 2;
3667 /* get text metrics and/or "average" char width of the specified logfont
3668 * for the specified dc */
3669 static void get_text_metr_size( HDC hdc
, LOGFONTW
*lf
, TEXTMETRICW
*metric
, UINT
*psz
)
3671 HFONT hfont
, hfontsav
;
3674 if (!metric
) metric
= &tm
;
3675 hfont
= NtGdiHfontCreate( lf
, sizeof(*lf
), 0, 0, NULL
);
3676 if (!hfont
|| !(hfontsav
= NtGdiSelectFont( hdc
, hfont
)))
3678 metric
->tmHeight
= -1;
3680 if (hfont
) NtGdiDeleteObjectApp( hfont
);
3683 ret
= get_char_dimensions( hdc
, metric
, NULL
);
3684 if (psz
) *psz
= ret
? ret
: 10;
3685 NtGdiSelectFont( hdc
, hfontsav
);
3686 NtGdiDeleteObjectApp( hfont
);
3689 DWORD
get_dialog_base_units(void)
3697 if ((hdc
= NtUserGetDC( 0 )))
3699 cx
= get_char_dimensions( hdc
, NULL
, &cy
);
3700 NtUserReleaseDC( 0, hdc
);
3702 TRACE( "base units = %d,%d\n", cx
, cy
);
3705 return MAKELONG( muldiv( cx
, get_system_dpi(), USER_DEFAULT_SCREEN_DPI
),
3706 muldiv( cy
, get_system_dpi(), USER_DEFAULT_SCREEN_DPI
));
3709 /* adjust some of the raw values found in the registry */
3710 static void normalize_nonclientmetrics( NONCLIENTMETRICSW
*pncm
)
3713 HDC hdc
= get_display_dc();
3715 if( pncm
->iBorderWidth
< 1) pncm
->iBorderWidth
= 1;
3716 if( pncm
->iCaptionWidth
< 8) pncm
->iCaptionWidth
= 8;
3717 if( pncm
->iScrollWidth
< 8) pncm
->iScrollWidth
= 8;
3718 if( pncm
->iScrollHeight
< 8) pncm
->iScrollHeight
= 8;
3720 /* adjust some heights to the corresponding font */
3721 get_text_metr_size( hdc
, &pncm
->lfMenuFont
, &tm
, NULL
);
3722 pncm
->iMenuHeight
= max( pncm
->iMenuHeight
, 2 + tm
.tmHeight
+ tm
.tmExternalLeading
);
3723 get_text_metr_size( hdc
, &pncm
->lfCaptionFont
, &tm
, NULL
);
3724 pncm
->iCaptionHeight
= max( pncm
->iCaptionHeight
, 2 + tm
.tmHeight
);
3725 get_text_metr_size( hdc
, &pncm
->lfSmCaptionFont
, &tm
, NULL
);
3726 pncm
->iSmCaptionHeight
= max( pncm
->iSmCaptionHeight
, 2 + tm
.tmHeight
);
3727 release_display_dc( hdc
);
3730 /* load a font (binary) parameter from the registry */
3731 static BOOL
get_font_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3735 if (!ptr_param
) return FALSE
;
3737 if (!entry
->hdr
.loaded
)
3739 switch (load_entry( &entry
->hdr
, &font
, sizeof(font
) ))
3742 if (font
.lfHeight
> 0) /* positive height value means points ( inch/72 ) */
3743 font
.lfHeight
= -muldiv( font
.lfHeight
, USER_DEFAULT_SCREEN_DPI
, 72 );
3744 entry
->font
.val
= font
;
3746 case sizeof(LOGFONT16
): /* win9x-winME format */
3747 logfont16to32( (LOGFONT16
*)&font
, &entry
->font
.val
);
3748 if (entry
->font
.val
.lfHeight
> 0)
3749 entry
->font
.val
.lfHeight
= -muldiv( entry
->font
.val
.lfHeight
, USER_DEFAULT_SCREEN_DPI
, 72 );
3752 WARN( "Unknown format in key %s value %s\n",
3753 debugstr_a( parameter_key_names
[entry
->hdr
.base_key
] ),
3754 debugstr_a( entry
->hdr
.regval
));
3756 case 0: /* use the default GUI font */
3757 NtGdiExtGetObjectW( GetStockObject( DEFAULT_GUI_FONT
), sizeof(font
), &font
);
3758 font
.lfHeight
= map_from_system_dpi( font
.lfHeight
);
3759 font
.lfWeight
= entry
->font
.weight
;
3760 entry
->font
.val
= font
;
3763 get_real_fontname( &entry
->font
.val
, entry
->font
.fullname
);
3764 entry
->hdr
.loaded
= TRUE
;
3766 font
= entry
->font
.val
;
3767 font
.lfHeight
= map_to_dpi( font
.lfHeight
, dpi
);
3768 lstrcpyW( font
.lfFaceName
, entry
->font
.fullname
);
3769 *(LOGFONTW
*)ptr_param
= font
;
3773 /* set a font (binary) parameter in the registry */
3774 static BOOL
set_font_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3779 memcpy( &font
, ptr_param
, sizeof(font
) );
3780 /* zero pad the end of lfFaceName so we don't save uninitialised data */
3781 for (ptr
= font
.lfFaceName
; ptr
< font
.lfFaceName
+ LF_FACESIZE
&& *ptr
; ptr
++);
3782 if (ptr
< font
.lfFaceName
+ LF_FACESIZE
)
3783 memset( ptr
, 0, (font
.lfFaceName
+ LF_FACESIZE
- ptr
) * sizeof(WCHAR
) );
3784 if (font
.lfHeight
< 0) font
.lfHeight
= map_from_system_dpi( font
.lfHeight
);
3786 if (!save_entry( &entry
->hdr
, &font
, sizeof(font
), REG_BINARY
, flags
)) return FALSE
;
3787 entry
->font
.val
= font
;
3788 get_real_fontname( &entry
->font
.val
, entry
->font
.fullname
);
3789 entry
->hdr
.loaded
= TRUE
;
3793 /* initialize a font (binary) parameter */
3794 static BOOL
init_font_entry( union sysparam_all_entry
*entry
)
3796 NtGdiExtGetObjectW( GetStockObject( DEFAULT_GUI_FONT
), sizeof(entry
->font
.val
), &entry
->font
.val
);
3797 entry
->font
.val
.lfHeight
= map_from_system_dpi( entry
->font
.val
.lfHeight
);
3798 entry
->font
.val
.lfWeight
= entry
->font
.weight
;
3799 get_real_fontname( &entry
->font
.val
, entry
->font
.fullname
);
3800 return init_entry( &entry
->hdr
, &entry
->font
.val
, sizeof(entry
->font
.val
), REG_BINARY
);
3803 /* get a user pref parameter in the registry */
3804 static BOOL
get_userpref_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3806 union sysparam_all_entry
*parent_entry
= entry
->pref
.parent
;
3809 if (!ptr_param
) return FALSE
;
3811 if (!parent_entry
->hdr
.get( parent_entry
, sizeof(prefs
), prefs
, dpi
)) return FALSE
;
3812 *(BOOL
*)ptr_param
= (prefs
[entry
->pref
.offset
] & entry
->pref
.mask
) != 0;
3816 /* set a user pref parameter in the registry */
3817 static BOOL
set_userpref_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3819 union sysparam_all_entry
*parent_entry
= entry
->pref
.parent
;
3822 parent_entry
->hdr
.loaded
= FALSE
; /* force loading it again */
3823 if (!parent_entry
->hdr
.get( parent_entry
, sizeof(prefs
), prefs
, get_system_dpi() )) return FALSE
;
3825 if (PtrToUlong( ptr_param
)) prefs
[entry
->pref
.offset
] |= entry
->pref
.mask
;
3826 else prefs
[entry
->pref
.offset
] &= ~entry
->pref
.mask
;
3828 return parent_entry
->hdr
.set( parent_entry
, sizeof(prefs
), prefs
, flags
);
3831 static BOOL
get_entry_dpi( void *ptr
, UINT int_param
, void *ptr_param
, UINT dpi
)
3833 union sysparam_all_entry
*entry
= ptr
;
3834 return entry
->hdr
.get( entry
, int_param
, ptr_param
, dpi
);
3837 static BOOL
get_entry( void *ptr
, UINT int_param
, void *ptr_param
)
3839 return get_entry_dpi( ptr
, int_param
, ptr_param
, get_system_dpi() );
3842 static BOOL
set_entry( void *ptr
, UINT int_param
, void *ptr_param
, UINT flags
)
3844 union sysparam_all_entry
*entry
= ptr
;
3845 return entry
->hdr
.set( entry
, int_param
, ptr_param
, flags
);
3848 #define UINT_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
3849 { .uint = { { get_uint_entry, set_uint_entry, init_uint_entry, base, reg }, (val) } }
3851 #define UINT_ENTRY_MIRROR(name,val,base,reg,mirror_base) union sysparam_all_entry entry_##name = \
3852 { .uint = { { get_uint_entry, set_uint_entry, init_uint_entry, base, reg, mirror_base, reg }, (val) } }
3854 #define INT_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
3855 { .uint = { { get_uint_entry, set_int_entry, init_int_entry, base, reg }, (val) } }
3857 #define BOOL_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
3858 { .bool = { { get_bool_entry, set_bool_entry, init_bool_entry, base, reg }, (val) } }
3860 #define BOOL_ENTRY_MIRROR(name,val,base,reg,mirror_base) union sysparam_all_entry entry_##name = \
3861 { .bool = { { get_bool_entry, set_bool_entry, init_bool_entry, base, reg, mirror_base, reg }, (val) } }
3863 #define TWIPS_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
3864 { .uint = { { get_twips_entry, set_twips_entry, init_int_entry, base, reg }, (val) } }
3866 #define YESNO_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
3867 { .bool = { { get_yesno_entry, set_yesno_entry, init_yesno_entry, base, reg }, (val) } }
3869 #define DWORD_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
3870 { .dword = { { get_dword_entry, set_dword_entry, init_dword_entry, base, reg }, (val) } }
3872 #define BINARY_ENTRY(name,data,base,reg) union sysparam_all_entry entry_##name = \
3873 { .bin = { { get_binary_entry, set_binary_entry, init_binary_entry, base, reg }, data, sizeof(data) } }
3875 #define PATH_ENTRY(name,base,reg,buffer) union sysparam_all_entry entry_##name = \
3876 { .path = { { get_path_entry, set_path_entry, init_path_entry, base, reg }, buffer } }
3878 #define FONT_ENTRY(name,weight,base,reg) union sysparam_all_entry entry_##name = \
3879 { .font = { { get_font_entry, set_font_entry, init_font_entry, base, reg }, (weight) } }
3881 #define USERPREF_ENTRY(name,offset,mask) union sysparam_all_entry entry_##name = \
3882 { .pref = { { get_userpref_entry, set_userpref_entry }, &entry_USERPREFERENCESMASK, (offset), (mask) } }
3884 static UINT_ENTRY( DRAGWIDTH
, 4, DESKTOP_KEY
, "DragWidth" );
3885 static UINT_ENTRY( DRAGHEIGHT
, 4, DESKTOP_KEY
, "DragHeight" );
3886 static UINT_ENTRY( DOUBLECLICKTIME
, 500, MOUSE_KEY
, "DoubleClickSpeed" );
3887 static UINT_ENTRY( FONTSMOOTHING
, 2, DESKTOP_KEY
, "FontSmoothing" );
3888 static UINT_ENTRY( GRIDGRANULARITY
, 0, DESKTOP_KEY
, "GridGranularity" );
3889 static UINT_ENTRY( KEYBOARDDELAY
, 1, KEYBOARD_KEY
, "KeyboardDelay" );
3890 static UINT_ENTRY( KEYBOARDSPEED
, 31, KEYBOARD_KEY
, "KeyboardSpeed" );
3891 static UINT_ENTRY( MENUSHOWDELAY
, 400, DESKTOP_KEY
, "MenuShowDelay" );
3892 static UINT_ENTRY( MINARRANGE
, ARW_HIDE
, METRICS_KEY
, "MinArrange" );
3893 static UINT_ENTRY( MINHORZGAP
, 0, METRICS_KEY
, "MinHorzGap" );
3894 static UINT_ENTRY( MINVERTGAP
, 0, METRICS_KEY
, "MinVertGap" );
3895 static UINT_ENTRY( MINWIDTH
, 154, METRICS_KEY
, "MinWidth" );
3896 static UINT_ENTRY( MOUSEHOVERHEIGHT
, 4, MOUSE_KEY
, "MouseHoverHeight" );
3897 static UINT_ENTRY( MOUSEHOVERTIME
, 400, MOUSE_KEY
, "MouseHoverTime" );
3898 static UINT_ENTRY( MOUSEHOVERWIDTH
, 4, MOUSE_KEY
, "MouseHoverWidth" );
3899 static UINT_ENTRY( MOUSESPEED
, 10, MOUSE_KEY
, "MouseSensitivity" );
3900 static UINT_ENTRY( MOUSETRAILS
, 0, MOUSE_KEY
, "MouseTrails" );
3901 static UINT_ENTRY( SCREENSAVETIMEOUT
, 300, DESKTOP_KEY
, "ScreenSaveTimeOut" );
3902 static UINT_ENTRY( WHEELSCROLLCHARS
, 3, DESKTOP_KEY
, "WheelScrollChars" );
3903 static UINT_ENTRY( WHEELSCROLLLINES
, 3, DESKTOP_KEY
, "WheelScrollLines" );
3904 static UINT_ENTRY_MIRROR( DOUBLECLKHEIGHT
, 4, MOUSE_KEY
, "DoubleClickHeight", DESKTOP_KEY
);
3905 static UINT_ENTRY_MIRROR( DOUBLECLKWIDTH
, 4, MOUSE_KEY
, "DoubleClickWidth", DESKTOP_KEY
);
3906 static UINT_ENTRY_MIRROR( MENUDROPALIGNMENT
, 0, DESKTOP_KEY
, "MenuDropAlignment", VERSION_KEY
);
3908 static INT_ENTRY( MOUSETHRESHOLD1
, 6, MOUSE_KEY
, "MouseThreshold1" );
3909 static INT_ENTRY( MOUSETHRESHOLD2
, 10, MOUSE_KEY
, "MouseThreshold2" );
3910 static INT_ENTRY( MOUSEACCELERATION
, 1, MOUSE_KEY
, "MouseSpeed" );
3912 static BOOL_ENTRY( BLOCKSENDINPUTRESETS
, FALSE
, DESKTOP_KEY
, "BlockSendInputResets" );
3913 static BOOL_ENTRY( DRAGFULLWINDOWS
, FALSE
, DESKTOP_KEY
, "DragFullWindows" );
3914 static BOOL_ENTRY( KEYBOARDPREF
, TRUE
, KEYBOARDPREF_KEY
, "On" );
3915 static BOOL_ENTRY( LOWPOWERACTIVE
, FALSE
, DESKTOP_KEY
, "LowPowerActive" );
3916 static BOOL_ENTRY( MOUSEBUTTONSWAP
, FALSE
, MOUSE_KEY
, "SwapMouseButtons" );
3917 static BOOL_ENTRY( POWEROFFACTIVE
, FALSE
, DESKTOP_KEY
, "PowerOffActive" );
3918 static BOOL_ENTRY( SCREENREADER
, FALSE
, SCREENREADER_KEY
, "On" );
3919 static BOOL_ENTRY( SCREENSAVEACTIVE
, TRUE
, DESKTOP_KEY
, "ScreenSaveActive" );
3920 static BOOL_ENTRY( SCREENSAVERRUNNING
, FALSE
, DESKTOP_KEY
, "WINE_ScreenSaverRunning" ); /* FIXME - real value */
3921 static BOOL_ENTRY( SHOWSOUNDS
, FALSE
, SHOWSOUNDS_KEY
, "On" );
3922 static BOOL_ENTRY( SNAPTODEFBUTTON
, FALSE
, MOUSE_KEY
, "SnapToDefaultButton" );
3923 static BOOL_ENTRY_MIRROR( ICONTITLEWRAP
, TRUE
, DESKTOP_KEY
, "IconTitleWrap", METRICS_KEY
);
3924 static BOOL_ENTRY( AUDIODESC_ON
, FALSE
, AUDIODESC_KEY
, "On" );
3926 static TWIPS_ENTRY( BORDER
, -15, METRICS_KEY
, "BorderWidth" );
3927 static TWIPS_ENTRY( CAPTIONHEIGHT
, -270, METRICS_KEY
, "CaptionHeight" );
3928 static TWIPS_ENTRY( CAPTIONWIDTH
, -270, METRICS_KEY
, "CaptionWidth" );
3929 static TWIPS_ENTRY( ICONHORIZONTALSPACING
, -1125, METRICS_KEY
, "IconSpacing" );
3930 static TWIPS_ENTRY( ICONVERTICALSPACING
, -1125, METRICS_KEY
, "IconVerticalSpacing" );
3931 static TWIPS_ENTRY( MENUHEIGHT
, -270, METRICS_KEY
, "MenuHeight" );
3932 static TWIPS_ENTRY( MENUWIDTH
, -270, METRICS_KEY
, "MenuWidth" );
3933 static TWIPS_ENTRY( PADDEDBORDERWIDTH
, 0, METRICS_KEY
, "PaddedBorderWidth" );
3934 static TWIPS_ENTRY( SCROLLHEIGHT
, -240, METRICS_KEY
, "ScrollHeight" );
3935 static TWIPS_ENTRY( SCROLLWIDTH
, -240, METRICS_KEY
, "ScrollWidth" );
3936 static TWIPS_ENTRY( SMCAPTIONHEIGHT
, -225, METRICS_KEY
, "SmCaptionHeight" );
3937 static TWIPS_ENTRY( SMCAPTIONWIDTH
, -225, METRICS_KEY
, "SmCaptionWidth" );
3939 static YESNO_ENTRY( BEEP
, TRUE
, SOUND_KEY
, "Beep" );
3941 static DWORD_ENTRY( ACTIVEWINDOWTRACKING
, 0, MOUSE_KEY
, "ActiveWindowTracking" );
3942 static DWORD_ENTRY( ACTIVEWNDTRKTIMEOUT
, 0, DESKTOP_KEY
, "ActiveWndTrackTimeout" );
3943 static DWORD_ENTRY( CARETWIDTH
, 1, DESKTOP_KEY
, "CaretWidth" );
3944 static DWORD_ENTRY( DPISCALINGVER
, 0, DESKTOP_KEY
, "DpiScalingVer" );
3945 static DWORD_ENTRY( FOCUSBORDERHEIGHT
, 1, DESKTOP_KEY
, "FocusBorderHeight" );
3946 static DWORD_ENTRY( FOCUSBORDERWIDTH
, 1, DESKTOP_KEY
, "FocusBorderWidth" );
3947 static DWORD_ENTRY( FONTSMOOTHINGCONTRAST
, 0, DESKTOP_KEY
, "FontSmoothingGamma" );
3948 static DWORD_ENTRY( FONTSMOOTHINGORIENTATION
, FE_FONTSMOOTHINGORIENTATIONRGB
, DESKTOP_KEY
, "FontSmoothingOrientation" );
3949 static DWORD_ENTRY( FONTSMOOTHINGTYPE
, FE_FONTSMOOTHINGSTANDARD
, DESKTOP_KEY
, "FontSmoothingType" );
3950 static DWORD_ENTRY( FOREGROUNDFLASHCOUNT
, 3, DESKTOP_KEY
, "ForegroundFlashCount" );
3951 static DWORD_ENTRY( FOREGROUNDLOCKTIMEOUT
, 0, DESKTOP_KEY
, "ForegroundLockTimeout" );
3952 static DWORD_ENTRY( LOGPIXELS
, 0, DESKTOP_KEY
, "LogPixels" );
3953 static DWORD_ENTRY( MOUSECLICKLOCKTIME
, 1200, DESKTOP_KEY
, "ClickLockTime" );
3954 static DWORD_ENTRY( AUDIODESC_LOCALE
, 0, AUDIODESC_KEY
, "Locale" );
3956 static WCHAR desk_pattern_path
[MAX_PATH
];
3957 static WCHAR desk_wallpaper_path
[MAX_PATH
];
3958 static PATH_ENTRY( DESKPATTERN
, DESKTOP_KEY
, "Pattern", desk_pattern_path
);
3959 static PATH_ENTRY( DESKWALLPAPER
, DESKTOP_KEY
, "Wallpaper", desk_wallpaper_path
);
3961 static BYTE user_prefs
[8] = { 0x30, 0x00, 0x00, 0x80, 0x12, 0x00, 0x00, 0x00 };
3962 static BINARY_ENTRY( USERPREFERENCESMASK
, user_prefs
, DESKTOP_KEY
, "UserPreferencesMask" );
3964 static FONT_ENTRY( CAPTIONLOGFONT
, FW_BOLD
, METRICS_KEY
, "CaptionFont" );
3965 static FONT_ENTRY( ICONTITLELOGFONT
, FW_NORMAL
, METRICS_KEY
, "IconFont" );
3966 static FONT_ENTRY( MENULOGFONT
, FW_NORMAL
, METRICS_KEY
, "MenuFont" );
3967 static FONT_ENTRY( MESSAGELOGFONT
, FW_NORMAL
, METRICS_KEY
, "MessageFont" );
3968 static FONT_ENTRY( SMCAPTIONLOGFONT
, FW_NORMAL
, METRICS_KEY
, "SmCaptionFont" );
3969 static FONT_ENTRY( STATUSLOGFONT
, FW_NORMAL
, METRICS_KEY
, "StatusFont" );
3971 static USERPREF_ENTRY( MENUANIMATION
, 0, 0x02 );
3972 static USERPREF_ENTRY( COMBOBOXANIMATION
, 0, 0x04 );
3973 static USERPREF_ENTRY( LISTBOXSMOOTHSCROLLING
, 0, 0x08 );
3974 static USERPREF_ENTRY( GRADIENTCAPTIONS
, 0, 0x10 );
3975 static USERPREF_ENTRY( KEYBOARDCUES
, 0, 0x20 );
3976 static USERPREF_ENTRY( ACTIVEWNDTRKZORDER
, 0, 0x40 );
3977 static USERPREF_ENTRY( HOTTRACKING
, 0, 0x80 );
3978 static USERPREF_ENTRY( MENUFADE
, 1, 0x02 );
3979 static USERPREF_ENTRY( SELECTIONFADE
, 1, 0x04 );
3980 static USERPREF_ENTRY( TOOLTIPANIMATION
, 1, 0x08 );
3981 static USERPREF_ENTRY( TOOLTIPFADE
, 1, 0x10 );
3982 static USERPREF_ENTRY( CURSORSHADOW
, 1, 0x20 );
3983 static USERPREF_ENTRY( MOUSESONAR
, 1, 0x40 );
3984 static USERPREF_ENTRY( MOUSECLICKLOCK
, 1, 0x80 );
3985 static USERPREF_ENTRY( MOUSEVANISH
, 2, 0x01 );
3986 static USERPREF_ENTRY( FLATMENU
, 2, 0x02 );
3987 static USERPREF_ENTRY( DROPSHADOW
, 2, 0x04 );
3988 static USERPREF_ENTRY( UIEFFECTS
, 3, 0x80 );
3989 static USERPREF_ENTRY( DISABLEOVERLAPPEDCONTENT
, 4, 0x01 );
3990 static USERPREF_ENTRY( CLIENTAREAANIMATION
, 4, 0x02 );
3991 static USERPREF_ENTRY( CLEARTYPE
, 4, 0x10 );
3992 static USERPREF_ENTRY( SPEECHRECOGNITION
, 4, 0x20 );
3994 /* System parameter indexes */
3997 SPI_SETWORKAREA_IDX
,
4001 /* indicators whether system parameter value is loaded */
4002 static char spi_loaded
[SPI_INDEX_COUNT
];
4004 static struct sysparam_rgb_entry system_colors
[] =
4006 #define RGB_ENTRY(name,val,reg) { { get_rgb_entry, set_rgb_entry, init_rgb_entry, COLORS_KEY, reg }, (val) }
4007 RGB_ENTRY( COLOR_SCROLLBAR
, RGB(212, 208, 200), "Scrollbar" ),
4008 RGB_ENTRY( COLOR_BACKGROUND
, RGB(58, 110, 165), "Background" ),
4009 RGB_ENTRY( COLOR_ACTIVECAPTION
, RGB(10, 36, 106), "ActiveTitle" ),
4010 RGB_ENTRY( COLOR_INACTIVECAPTION
, RGB(128, 128, 128), "InactiveTitle" ),
4011 RGB_ENTRY( COLOR_MENU
, RGB(212, 208, 200), "Menu" ),
4012 RGB_ENTRY( COLOR_WINDOW
, RGB(255, 255, 255), "Window" ),
4013 RGB_ENTRY( COLOR_WINDOWFRAME
, RGB(0, 0, 0), "WindowFrame" ),
4014 RGB_ENTRY( COLOR_MENUTEXT
, RGB(0, 0, 0), "MenuText" ),
4015 RGB_ENTRY( COLOR_WINDOWTEXT
, RGB(0, 0, 0), "WindowText" ),
4016 RGB_ENTRY( COLOR_CAPTIONTEXT
, RGB(255, 255, 255), "TitleText" ),
4017 RGB_ENTRY( COLOR_ACTIVEBORDER
, RGB(212, 208, 200), "ActiveBorder" ),
4018 RGB_ENTRY( COLOR_INACTIVEBORDER
, RGB(212, 208, 200), "InactiveBorder" ),
4019 RGB_ENTRY( COLOR_APPWORKSPACE
, RGB(128, 128, 128), "AppWorkSpace" ),
4020 RGB_ENTRY( COLOR_HIGHLIGHT
, RGB(10, 36, 106), "Hilight" ),
4021 RGB_ENTRY( COLOR_HIGHLIGHTTEXT
, RGB(255, 255, 255), "HilightText" ),
4022 RGB_ENTRY( COLOR_BTNFACE
, RGB(212, 208, 200), "ButtonFace" ),
4023 RGB_ENTRY( COLOR_BTNSHADOW
, RGB(128, 128, 128), "ButtonShadow" ),
4024 RGB_ENTRY( COLOR_GRAYTEXT
, RGB(128, 128, 128), "GrayText" ),
4025 RGB_ENTRY( COLOR_BTNTEXT
, RGB(0, 0, 0), "ButtonText" ),
4026 RGB_ENTRY( COLOR_INACTIVECAPTIONTEXT
, RGB(212, 208, 200), "InactiveTitleText" ),
4027 RGB_ENTRY( COLOR_BTNHIGHLIGHT
, RGB(255, 255, 255), "ButtonHilight" ),
4028 RGB_ENTRY( COLOR_3DDKSHADOW
, RGB(64, 64, 64), "ButtonDkShadow" ),
4029 RGB_ENTRY( COLOR_3DLIGHT
, RGB(212, 208, 200), "ButtonLight" ),
4030 RGB_ENTRY( COLOR_INFOTEXT
, RGB(0, 0, 0), "InfoText" ),
4031 RGB_ENTRY( COLOR_INFOBK
, RGB(255, 255, 225), "InfoWindow" ),
4032 RGB_ENTRY( COLOR_ALTERNATEBTNFACE
, RGB(181, 181, 181), "ButtonAlternateFace" ),
4033 RGB_ENTRY( COLOR_HOTLIGHT
, RGB(0, 0, 200), "HotTrackingColor" ),
4034 RGB_ENTRY( COLOR_GRADIENTACTIVECAPTION
, RGB(166, 202, 240), "GradientActiveTitle" ),
4035 RGB_ENTRY( COLOR_GRADIENTINACTIVECAPTION
, RGB(192, 192, 192), "GradientInactiveTitle" ),
4036 RGB_ENTRY( COLOR_MENUHILIGHT
, RGB(10, 36, 106), "MenuHilight" ),
4037 RGB_ENTRY( COLOR_MENUBAR
, RGB(212, 208, 200), "MenuBar" )
4041 /* entries that are initialized by default in the registry */
4042 static union sysparam_all_entry
* const default_entries
[] =
4044 (union sysparam_all_entry
*)&entry_ACTIVEWINDOWTRACKING
,
4045 (union sysparam_all_entry
*)&entry_ACTIVEWNDTRKTIMEOUT
,
4046 (union sysparam_all_entry
*)&entry_BEEP
,
4047 (union sysparam_all_entry
*)&entry_BLOCKSENDINPUTRESETS
,
4048 (union sysparam_all_entry
*)&entry_BORDER
,
4049 (union sysparam_all_entry
*)&entry_CAPTIONHEIGHT
,
4050 (union sysparam_all_entry
*)&entry_CAPTIONWIDTH
,
4051 (union sysparam_all_entry
*)&entry_CARETWIDTH
,
4052 (union sysparam_all_entry
*)&entry_DESKWALLPAPER
,
4053 (union sysparam_all_entry
*)&entry_DOUBLECLICKTIME
,
4054 (union sysparam_all_entry
*)&entry_DOUBLECLKHEIGHT
,
4055 (union sysparam_all_entry
*)&entry_DOUBLECLKWIDTH
,
4056 (union sysparam_all_entry
*)&entry_DRAGFULLWINDOWS
,
4057 (union sysparam_all_entry
*)&entry_DRAGHEIGHT
,
4058 (union sysparam_all_entry
*)&entry_DRAGWIDTH
,
4059 (union sysparam_all_entry
*)&entry_FOCUSBORDERHEIGHT
,
4060 (union sysparam_all_entry
*)&entry_FOCUSBORDERWIDTH
,
4061 (union sysparam_all_entry
*)&entry_FONTSMOOTHING
,
4062 (union sysparam_all_entry
*)&entry_FONTSMOOTHINGCONTRAST
,
4063 (union sysparam_all_entry
*)&entry_FONTSMOOTHINGORIENTATION
,
4064 (union sysparam_all_entry
*)&entry_FONTSMOOTHINGTYPE
,
4065 (union sysparam_all_entry
*)&entry_FOREGROUNDFLASHCOUNT
,
4066 (union sysparam_all_entry
*)&entry_FOREGROUNDLOCKTIMEOUT
,
4067 (union sysparam_all_entry
*)&entry_ICONHORIZONTALSPACING
,
4068 (union sysparam_all_entry
*)&entry_ICONTITLEWRAP
,
4069 (union sysparam_all_entry
*)&entry_ICONVERTICALSPACING
,
4070 (union sysparam_all_entry
*)&entry_KEYBOARDDELAY
,
4071 (union sysparam_all_entry
*)&entry_KEYBOARDPREF
,
4072 (union sysparam_all_entry
*)&entry_KEYBOARDSPEED
,
4073 (union sysparam_all_entry
*)&entry_LOWPOWERACTIVE
,
4074 (union sysparam_all_entry
*)&entry_MENUHEIGHT
,
4075 (union sysparam_all_entry
*)&entry_MENUSHOWDELAY
,
4076 (union sysparam_all_entry
*)&entry_MENUWIDTH
,
4077 (union sysparam_all_entry
*)&entry_MOUSEACCELERATION
,
4078 (union sysparam_all_entry
*)&entry_MOUSEBUTTONSWAP
,
4079 (union sysparam_all_entry
*)&entry_MOUSECLICKLOCKTIME
,
4080 (union sysparam_all_entry
*)&entry_MOUSEHOVERHEIGHT
,
4081 (union sysparam_all_entry
*)&entry_MOUSEHOVERTIME
,
4082 (union sysparam_all_entry
*)&entry_MOUSEHOVERWIDTH
,
4083 (union sysparam_all_entry
*)&entry_MOUSESPEED
,
4084 (union sysparam_all_entry
*)&entry_MOUSETHRESHOLD1
,
4085 (union sysparam_all_entry
*)&entry_MOUSETHRESHOLD2
,
4086 (union sysparam_all_entry
*)&entry_PADDEDBORDERWIDTH
,
4087 (union sysparam_all_entry
*)&entry_SCREENREADER
,
4088 (union sysparam_all_entry
*)&entry_SCROLLHEIGHT
,
4089 (union sysparam_all_entry
*)&entry_SCROLLWIDTH
,
4090 (union sysparam_all_entry
*)&entry_SHOWSOUNDS
,
4091 (union sysparam_all_entry
*)&entry_SMCAPTIONHEIGHT
,
4092 (union sysparam_all_entry
*)&entry_SMCAPTIONWIDTH
,
4093 (union sysparam_all_entry
*)&entry_SNAPTODEFBUTTON
,
4094 (union sysparam_all_entry
*)&entry_USERPREFERENCESMASK
,
4095 (union sysparam_all_entry
*)&entry_WHEELSCROLLCHARS
,
4096 (union sysparam_all_entry
*)&entry_WHEELSCROLLLINES
,
4097 (union sysparam_all_entry
*)&entry_AUDIODESC_LOCALE
,
4098 (union sysparam_all_entry
*)&entry_AUDIODESC_ON
,
4101 void sysparams_init(void)
4104 DWORD i
, dispos
, dpi_scaling
;
4105 WCHAR layout
[KL_NAMELENGTH
];
4106 pthread_mutexattr_t attr
;
4109 static const WCHAR software_wineW
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e'};
4110 static const WCHAR temporary_system_parametersW
[] =
4111 {'T','e','m','p','o','r','a','r','y',' ','S','y','s','t','e','m',' ',
4112 'P','a','r','a','m','e','t','e','r','s'};
4113 static const WCHAR oneW
[] = {'1',0};
4114 static const WCHAR kl_preloadW
[] =
4115 {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d'};
4117 pthread_mutexattr_init( &attr
);
4118 pthread_mutexattr_settype( &attr
, PTHREAD_MUTEX_RECURSIVE
);
4119 pthread_mutex_init( &user_mutex
, &attr
);
4120 pthread_mutexattr_destroy( &attr
);
4122 if ((hkey
= reg_create_key( hkcu_key
, kl_preloadW
, sizeof(kl_preloadW
), 0, NULL
)))
4124 if (NtUserGetKeyboardLayoutName( layout
))
4125 set_reg_value( hkey
, oneW
, REG_SZ
, (const BYTE
*)layout
,
4126 (lstrlenW(layout
) + 1) * sizeof(WCHAR
) );
4130 /* this one must be non-volatile */
4131 if (!(hkey
= reg_create_key( hkcu_key
, software_wineW
, sizeof(software_wineW
), 0, NULL
)))
4133 ERR("Can't create wine registry branch\n");
4137 /* @@ Wine registry key: HKCU\Software\Wine\Temporary System Parameters */
4138 if (!(volatile_base_key
= reg_create_key( hkey
, temporary_system_parametersW
,
4139 sizeof(temporary_system_parametersW
),
4140 REG_OPTION_VOLATILE
, &dispos
)))
4141 ERR("Can't create non-permanent wine registry branch\n");
4145 config_key
= reg_create_key( NULL
, config_keyW
, sizeof(config_keyW
), 0, NULL
);
4147 get_dword_entry( (union sysparam_all_entry
*)&entry_LOGPIXELS
, 0, &system_dpi
, 0 );
4148 if (!system_dpi
) /* check fallback key */
4150 static const WCHAR log_pixelsW
[] = {'L','o','g','P','i','x','e','l','s',0};
4151 static const WCHAR software_fontsW
[] =
4152 {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s'};
4154 if ((hkey
= reg_open_key( config_key
, software_fontsW
, sizeof(software_fontsW
) )))
4156 char buffer
[offsetof(KEY_VALUE_PARTIAL_INFORMATION
, Data
[sizeof(DWORD
)])];
4157 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
4159 if (query_reg_value( hkey
, log_pixelsW
, value
, sizeof(buffer
) ) && value
->Type
== REG_DWORD
)
4160 system_dpi
= *(const DWORD
*)value
->Data
;
4164 if (!system_dpi
) system_dpi
= USER_DEFAULT_SCREEN_DPI
;
4166 /* FIXME: what do the DpiScalingVer flags mean? */
4167 get_dword_entry( (union sysparam_all_entry
*)&entry_DPISCALINGVER
, 0, &dpi_scaling
, 0 );
4168 if (!dpi_scaling
) NtUserSetProcessDpiAwarenessContext( NTUSER_DPI_PER_MONITOR_AWARE
, 0 );
4170 if (volatile_base_key
&& dispos
== REG_CREATED_NEW_KEY
) /* first process, initialize entries */
4172 for (i
= 0; i
< ARRAY_SIZE( default_entries
); i
++)
4173 default_entries
[i
]->hdr
.init( default_entries
[i
] );
4177 static BOOL
update_desktop_wallpaper(void)
4179 /* FIXME: move implementation from user32 */
4180 entry_DESKWALLPAPER
.hdr
.loaded
= entry_DESKPATTERN
.hdr
.loaded
= FALSE
;
4184 /***********************************************************************
4185 * NtUserSystemParametersInfoForDpi (win32u.@)
4187 BOOL WINAPI
NtUserSystemParametersInfoForDpi( UINT action
, UINT val
, PVOID ptr
, UINT winini
, UINT dpi
)
4193 case SPI_GETICONTITLELOGFONT
:
4194 ret
= get_entry_dpi( &entry_ICONTITLELOGFONT
, val
, ptr
, dpi
);
4196 case SPI_GETNONCLIENTMETRICS
:
4198 NONCLIENTMETRICSW
*ncm
= ptr
;
4201 ret
= get_entry_dpi( &entry_BORDER
, 0, &ncm
->iBorderWidth
, dpi
) &&
4202 get_entry_dpi( &entry_SCROLLWIDTH
, 0, &ncm
->iScrollWidth
, dpi
) &&
4203 get_entry_dpi( &entry_SCROLLHEIGHT
, 0, &ncm
->iScrollHeight
, dpi
) &&
4204 get_entry_dpi( &entry_CAPTIONWIDTH
, 0, &ncm
->iCaptionWidth
, dpi
) &&
4205 get_entry_dpi( &entry_CAPTIONHEIGHT
, 0, &ncm
->iCaptionHeight
, dpi
) &&
4206 get_entry_dpi( &entry_CAPTIONLOGFONT
, 0, &ncm
->lfCaptionFont
, dpi
) &&
4207 get_entry_dpi( &entry_SMCAPTIONWIDTH
, 0, &ncm
->iSmCaptionWidth
, dpi
) &&
4208 get_entry_dpi( &entry_SMCAPTIONHEIGHT
, 0, &ncm
->iSmCaptionHeight
, dpi
) &&
4209 get_entry_dpi( &entry_SMCAPTIONLOGFONT
, 0, &ncm
->lfSmCaptionFont
, dpi
) &&
4210 get_entry_dpi( &entry_MENUWIDTH
, 0, &ncm
->iMenuWidth
, dpi
) &&
4211 get_entry_dpi( &entry_MENUHEIGHT
, 0, &ncm
->iMenuHeight
, dpi
) &&
4212 get_entry_dpi( &entry_MENULOGFONT
, 0, &ncm
->lfMenuFont
, dpi
) &&
4213 get_entry_dpi( &entry_STATUSLOGFONT
, 0, &ncm
->lfStatusFont
, dpi
) &&
4214 get_entry_dpi( &entry_MESSAGELOGFONT
, 0, &ncm
->lfMessageFont
, dpi
);
4215 if (ret
&& ncm
->cbSize
== sizeof(NONCLIENTMETRICSW
))
4216 ret
= get_entry_dpi( &entry_PADDEDBORDERWIDTH
, 0, &ncm
->iPaddedBorderWidth
, dpi
);
4217 normalize_nonclientmetrics( ncm
);
4220 case SPI_GETICONMETRICS
:
4222 ICONMETRICSW
*im
= ptr
;
4223 if (im
&& im
->cbSize
== sizeof(*im
))
4224 ret
= get_entry_dpi( &entry_ICONHORIZONTALSPACING
, 0, &im
->iHorzSpacing
, dpi
) &&
4225 get_entry_dpi( &entry_ICONVERTICALSPACING
, 0, &im
->iVertSpacing
, dpi
) &&
4226 get_entry_dpi( &entry_ICONTITLEWRAP
, 0, &im
->iTitleWrap
, dpi
) &&
4227 get_entry_dpi( &entry_ICONTITLELOGFONT
, 0, &im
->lfFont
, dpi
);
4231 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4237 /***********************************************************************
4238 * NtUserSystemParametersInfo (win32u.@)
4240 * Each system parameter has flag which shows whether the parameter
4241 * is loaded or not. Parameters, stored directly in SysParametersInfo are
4242 * loaded from registry only when they are requested and the flag is
4243 * "false", after the loading the flag is set to "true". On interprocess
4244 * notification of the parameter change the corresponding parameter flag is
4245 * set to "false". The parameter value will be reloaded when it is requested
4247 * Parameters, backed by or depend on GetSystemMetrics are processed
4248 * differently. These parameters are always loaded. They are reloaded right
4249 * away on interprocess change notification. We can't do lazy loading because
4250 * we don't want to complicate GetSystemMetrics.
4251 * Parameters backed by driver settings are read from corresponding setting.
4252 * On the parameter change request the setting is changed. Interprocess change
4253 * notifications are ignored.
4254 * When parameter value is updated the changed value is stored in permanent
4255 * registry branch if saving is requested. Otherwise it is stored
4256 * in temporary branch
4258 * Some SPI values can also be stored as Twips values in the registry,
4259 * don't forget the conversion!
4261 BOOL WINAPI
NtUserSystemParametersInfo( UINT action
, UINT val
, void *ptr
, UINT winini
)
4263 #define WINE_SPI_FIXME(x) \
4266 static BOOL warn = TRUE; \
4270 FIXME( "Unimplemented action: %u (%s)\n", x, #x ); \
4273 RtlSetLastWin32Error( ERROR_INVALID_SPI_VALUE ); \
4276 #define WINE_SPI_WARN(x) \
4278 WARN( "Ignored action: %u (%s)\n", x, #x ); \
4282 BOOL ret
= user_driver
->pSystemParametersInfo( action
, val
, ptr
, winini
);
4283 unsigned spi_idx
= 0;
4285 if (!ret
) switch (action
)
4288 ret
= get_entry( &entry_BEEP
, val
, ptr
);
4291 ret
= set_entry( &entry_BEEP
, val
, ptr
, winini
);
4294 ret
= get_entry( &entry_MOUSETHRESHOLD1
, val
, (INT
*)ptr
) &&
4295 get_entry( &entry_MOUSETHRESHOLD2
, val
, (INT
*)ptr
+ 1 ) &&
4296 get_entry( &entry_MOUSEACCELERATION
, val
, (INT
*)ptr
+ 2 );
4299 ret
= set_entry( &entry_MOUSETHRESHOLD1
, ((INT
*)ptr
)[0], ptr
, winini
) &&
4300 set_entry( &entry_MOUSETHRESHOLD2
, ((INT
*)ptr
)[1], ptr
, winini
) &&
4301 set_entry( &entry_MOUSEACCELERATION
, ((INT
*)ptr
)[2], ptr
, winini
);
4304 ret
= get_entry( &entry_BORDER
, val
, ptr
);
4305 if (*(INT
*)ptr
< 1) *(INT
*)ptr
= 1;
4308 ret
= set_entry( &entry_BORDER
, val
, ptr
, winini
);
4310 case SPI_GETKEYBOARDSPEED
:
4311 ret
= get_entry( &entry_KEYBOARDSPEED
, val
, ptr
);
4313 case SPI_SETKEYBOARDSPEED
:
4314 if (val
> 31) val
= 31;
4315 ret
= set_entry( &entry_KEYBOARDSPEED
, val
, ptr
, winini
);
4318 WINE_SPI_WARN(SPI_LANGDRIVER
); /* not implemented in Windows */
4320 case SPI_ICONHORIZONTALSPACING
:
4322 ret
= get_entry( &entry_ICONHORIZONTALSPACING
, val
, ptr
);
4325 int min_val
= map_to_dpi( 32, get_system_dpi() );
4326 ret
= set_entry( &entry_ICONHORIZONTALSPACING
, max( min_val
, val
), ptr
, winini
);
4329 case SPI_GETSCREENSAVETIMEOUT
:
4330 ret
= get_entry( &entry_SCREENSAVETIMEOUT
, val
, ptr
);
4332 case SPI_SETSCREENSAVETIMEOUT
:
4333 ret
= set_entry( &entry_SCREENSAVETIMEOUT
, val
, ptr
, winini
);
4335 case SPI_GETSCREENSAVEACTIVE
:
4336 ret
= get_entry( &entry_SCREENSAVEACTIVE
, val
, ptr
);
4338 case SPI_SETSCREENSAVEACTIVE
:
4339 ret
= set_entry( &entry_SCREENSAVEACTIVE
, val
, ptr
, winini
);
4341 case SPI_GETGRIDGRANULARITY
:
4342 ret
= get_entry( &entry_GRIDGRANULARITY
, val
, ptr
);
4344 case SPI_SETGRIDGRANULARITY
:
4345 ret
= set_entry( &entry_GRIDGRANULARITY
, val
, ptr
, winini
);
4347 case SPI_SETDESKWALLPAPER
:
4348 if (!ptr
|| set_entry( &entry_DESKWALLPAPER
, val
, ptr
, winini
))
4349 ret
= update_desktop_wallpaper();
4351 case SPI_SETDESKPATTERN
:
4352 if (!ptr
|| set_entry( &entry_DESKPATTERN
, val
, ptr
, winini
))
4353 ret
= update_desktop_wallpaper();
4355 case SPI_GETKEYBOARDDELAY
:
4356 ret
= get_entry( &entry_KEYBOARDDELAY
, val
, ptr
);
4358 case SPI_SETKEYBOARDDELAY
:
4359 ret
= set_entry( &entry_KEYBOARDDELAY
, val
, ptr
, winini
);
4361 case SPI_ICONVERTICALSPACING
:
4363 ret
= get_entry( &entry_ICONVERTICALSPACING
, val
, ptr
);
4366 int min_val
= map_to_dpi( 32, get_system_dpi() );
4367 ret
= set_entry( &entry_ICONVERTICALSPACING
, max( min_val
, val
), ptr
, winini
);
4370 case SPI_GETICONTITLEWRAP
:
4371 ret
= get_entry( &entry_ICONTITLEWRAP
, val
, ptr
);
4373 case SPI_SETICONTITLEWRAP
:
4374 ret
= set_entry( &entry_ICONTITLEWRAP
, val
, ptr
, winini
);
4376 case SPI_GETMENUDROPALIGNMENT
:
4377 ret
= get_entry( &entry_MENUDROPALIGNMENT
, val
, ptr
);
4379 case SPI_SETMENUDROPALIGNMENT
:
4380 ret
= set_entry( &entry_MENUDROPALIGNMENT
, val
, ptr
, winini
);
4382 case SPI_SETDOUBLECLKWIDTH
:
4383 ret
= set_entry( &entry_DOUBLECLKWIDTH
, val
, ptr
, winini
);
4385 case SPI_SETDOUBLECLKHEIGHT
:
4386 ret
= set_entry( &entry_DOUBLECLKHEIGHT
, val
, ptr
, winini
);
4388 case SPI_GETICONTITLELOGFONT
:
4389 ret
= get_entry( &entry_ICONTITLELOGFONT
, val
, ptr
);
4391 case SPI_SETDOUBLECLICKTIME
:
4392 ret
= set_entry( &entry_DOUBLECLICKTIME
, val
, ptr
, winini
);
4394 case SPI_SETMOUSEBUTTONSWAP
:
4395 ret
= set_entry( &entry_MOUSEBUTTONSWAP
, val
, ptr
, winini
);
4397 case SPI_SETICONTITLELOGFONT
:
4398 ret
= set_entry( &entry_ICONTITLELOGFONT
, val
, ptr
, winini
);
4400 case SPI_GETFASTTASKSWITCH
:
4401 if (!ptr
) return FALSE
;
4402 *(BOOL
*)ptr
= TRUE
;
4405 case SPI_SETFASTTASKSWITCH
:
4406 /* the action is disabled */
4409 case SPI_SETDRAGFULLWINDOWS
:
4410 ret
= set_entry( &entry_DRAGFULLWINDOWS
, val
, ptr
, winini
);
4412 case SPI_GETDRAGFULLWINDOWS
:
4413 ret
= get_entry( &entry_DRAGFULLWINDOWS
, val
, ptr
);
4415 case SPI_GETNONCLIENTMETRICS
:
4417 NONCLIENTMETRICSW
*nm
= ptr
;
4420 if (!ptr
) return FALSE
;
4422 ret
= get_entry( &entry_BORDER
, 0, &nm
->iBorderWidth
) &&
4423 get_entry( &entry_PADDEDBORDERWIDTH
, 0, &padded_border
) &&
4424 get_entry( &entry_SCROLLWIDTH
, 0, &nm
->iScrollWidth
) &&
4425 get_entry( &entry_SCROLLHEIGHT
, 0, &nm
->iScrollHeight
) &&
4426 get_entry( &entry_CAPTIONWIDTH
, 0, &nm
->iCaptionWidth
) &&
4427 get_entry( &entry_CAPTIONHEIGHT
, 0, &nm
->iCaptionHeight
) &&
4428 get_entry( &entry_CAPTIONLOGFONT
, 0, &nm
->lfCaptionFont
) &&
4429 get_entry( &entry_SMCAPTIONWIDTH
, 0, &nm
->iSmCaptionWidth
) &&
4430 get_entry( &entry_SMCAPTIONHEIGHT
, 0, &nm
->iSmCaptionHeight
) &&
4431 get_entry( &entry_SMCAPTIONLOGFONT
, 0, &nm
->lfSmCaptionFont
) &&
4432 get_entry( &entry_MENUWIDTH
, 0, &nm
->iMenuWidth
) &&
4433 get_entry( &entry_MENUHEIGHT
, 0, &nm
->iMenuHeight
) &&
4434 get_entry( &entry_MENULOGFONT
, 0, &nm
->lfMenuFont
) &&
4435 get_entry( &entry_STATUSLOGFONT
, 0, &nm
->lfStatusFont
) &&
4436 get_entry( &entry_MESSAGELOGFONT
, 0, &nm
->lfMessageFont
);
4439 nm
->iBorderWidth
+= padded_border
;
4440 if (nm
->cbSize
== sizeof(NONCLIENTMETRICSW
)) nm
->iPaddedBorderWidth
= 0;
4442 normalize_nonclientmetrics( nm
);
4445 case SPI_SETNONCLIENTMETRICS
:
4447 LPNONCLIENTMETRICSW nm
= ptr
;
4450 if (nm
&& (nm
->cbSize
== sizeof(NONCLIENTMETRICSW
) ||
4451 nm
->cbSize
== FIELD_OFFSET(NONCLIENTMETRICSW
, iPaddedBorderWidth
)))
4453 get_entry( &entry_PADDEDBORDERWIDTH
, 0, &padded_border
);
4455 ret
= set_entry( &entry_BORDER
, nm
->iBorderWidth
- padded_border
, NULL
, winini
) &&
4456 set_entry( &entry_SCROLLWIDTH
, nm
->iScrollWidth
, NULL
, winini
) &&
4457 set_entry( &entry_SCROLLHEIGHT
, nm
->iScrollHeight
, NULL
, winini
) &&
4458 set_entry( &entry_CAPTIONWIDTH
, nm
->iCaptionWidth
, NULL
, winini
) &&
4459 set_entry( &entry_CAPTIONHEIGHT
, nm
->iCaptionHeight
, NULL
, winini
) &&
4460 set_entry( &entry_SMCAPTIONWIDTH
, nm
->iSmCaptionWidth
, NULL
, winini
) &&
4461 set_entry( &entry_SMCAPTIONHEIGHT
, nm
->iSmCaptionHeight
, NULL
, winini
) &&
4462 set_entry( &entry_MENUWIDTH
, nm
->iMenuWidth
, NULL
, winini
) &&
4463 set_entry( &entry_MENUHEIGHT
, nm
->iMenuHeight
, NULL
, winini
) &&
4464 set_entry( &entry_MENULOGFONT
, 0, &nm
->lfMenuFont
, winini
) &&
4465 set_entry( &entry_CAPTIONLOGFONT
, 0, &nm
->lfCaptionFont
, winini
) &&
4466 set_entry( &entry_SMCAPTIONLOGFONT
, 0, &nm
->lfSmCaptionFont
, winini
) &&
4467 set_entry( &entry_STATUSLOGFONT
, 0, &nm
->lfStatusFont
, winini
) &&
4468 set_entry( &entry_MESSAGELOGFONT
, 0, &nm
->lfMessageFont
, winini
);
4472 case SPI_GETMINIMIZEDMETRICS
:
4474 MINIMIZEDMETRICS
*mm
= ptr
;
4475 if (mm
&& mm
->cbSize
== sizeof(*mm
)) {
4476 ret
= get_entry( &entry_MINWIDTH
, 0, &mm
->iWidth
) &&
4477 get_entry( &entry_MINHORZGAP
, 0, &mm
->iHorzGap
) &&
4478 get_entry( &entry_MINVERTGAP
, 0, &mm
->iVertGap
) &&
4479 get_entry( &entry_MINARRANGE
, 0, &mm
->iArrange
);
4480 mm
->iWidth
= max( 0, mm
->iWidth
);
4481 mm
->iHorzGap
= max( 0, mm
->iHorzGap
);
4482 mm
->iVertGap
= max( 0, mm
->iVertGap
);
4483 mm
->iArrange
&= 0x0f;
4487 case SPI_SETMINIMIZEDMETRICS
:
4489 MINIMIZEDMETRICS
*mm
= ptr
;
4490 if (mm
&& mm
->cbSize
== sizeof(*mm
))
4491 ret
= set_entry( &entry_MINWIDTH
, max( 0, mm
->iWidth
), NULL
, winini
) &&
4492 set_entry( &entry_MINHORZGAP
, max( 0, mm
->iHorzGap
), NULL
, winini
) &&
4493 set_entry( &entry_MINVERTGAP
, max( 0, mm
->iVertGap
), NULL
, winini
) &&
4494 set_entry( &entry_MINARRANGE
, mm
->iArrange
& 0x0f, NULL
, winini
);
4497 case SPI_GETICONMETRICS
:
4499 ICONMETRICSW
*icon
= ptr
;
4500 if(icon
&& icon
->cbSize
== sizeof(*icon
))
4502 ret
= get_entry( &entry_ICONHORIZONTALSPACING
, 0, &icon
->iHorzSpacing
) &&
4503 get_entry( &entry_ICONVERTICALSPACING
, 0, &icon
->iVertSpacing
) &&
4504 get_entry( &entry_ICONTITLEWRAP
, 0, &icon
->iTitleWrap
) &&
4505 get_entry( &entry_ICONTITLELOGFONT
, 0, &icon
->lfFont
);
4509 case SPI_SETICONMETRICS
:
4511 ICONMETRICSW
*icon
= ptr
;
4512 if (icon
&& icon
->cbSize
== sizeof(*icon
))
4513 ret
= set_entry( &entry_ICONVERTICALSPACING
, max(32,icon
->iVertSpacing
), NULL
, winini
) &&
4514 set_entry( &entry_ICONHORIZONTALSPACING
, max(32,icon
->iHorzSpacing
), NULL
, winini
) &&
4515 set_entry( &entry_ICONTITLEWRAP
, icon
->iTitleWrap
, NULL
, winini
) &&
4516 set_entry( &entry_ICONTITLELOGFONT
, 0, &icon
->lfFont
, winini
);
4519 case SPI_SETWORKAREA
:
4521 if (!ptr
) return FALSE
;
4522 spi_idx
= SPI_SETWORKAREA_IDX
;
4523 work_area
= *(RECT
*)ptr
;
4524 spi_loaded
[spi_idx
] = TRUE
;
4528 case SPI_GETWORKAREA
:
4530 if (!ptr
) return FALSE
;
4532 spi_idx
= SPI_SETWORKAREA_IDX
;
4533 if (!spi_loaded
[spi_idx
])
4535 struct monitor
*monitor
;
4537 if (!lock_display_devices()) return FALSE
;
4539 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
4541 if (!(monitor
->flags
& MONITORINFOF_PRIMARY
)) continue;
4542 work_area
= monitor
->rc_work
;
4546 unlock_display_devices();
4547 spi_loaded
[spi_idx
] = TRUE
;
4549 *(RECT
*)ptr
= map_dpi_rect( work_area
, system_dpi
, get_thread_dpi() );
4551 TRACE("work area %s\n", wine_dbgstr_rect( &work_area
));
4555 WINE_SPI_FIXME(SPI_SETPENWINDOWS
);
4557 case SPI_GETFILTERKEYS
:
4559 LPFILTERKEYS filter_keys
= ptr
;
4560 WARN("SPI_GETFILTERKEYS not fully implemented\n");
4561 if (filter_keys
&& filter_keys
->cbSize
== sizeof(FILTERKEYS
))
4563 /* Indicate that no FilterKeys feature available */
4564 filter_keys
->dwFlags
= 0;
4565 filter_keys
->iWaitMSec
= 0;
4566 filter_keys
->iDelayMSec
= 0;
4567 filter_keys
->iRepeatMSec
= 0;
4568 filter_keys
->iBounceMSec
= 0;
4573 WINE_SPI_FIXME(SPI_SETFILTERKEYS
);
4575 case SPI_GETTOGGLEKEYS
:
4577 LPTOGGLEKEYS toggle_keys
= ptr
;
4578 WARN("SPI_GETTOGGLEKEYS not fully implemented\n");
4579 if (toggle_keys
&& toggle_keys
->cbSize
== sizeof(TOGGLEKEYS
))
4581 /* Indicate that no ToggleKeys feature available */
4582 toggle_keys
->dwFlags
= 0;
4588 WINE_SPI_FIXME(SPI_SETTOGGLEKEYS
);
4590 case SPI_GETMOUSEKEYS
:
4592 MOUSEKEYS
*mouse_keys
= ptr
;
4593 WARN("SPI_GETMOUSEKEYS not fully implemented\n");
4594 if (mouse_keys
&& mouse_keys
->cbSize
== sizeof(MOUSEKEYS
))
4596 /* Indicate that no MouseKeys feature available */
4597 mouse_keys
->dwFlags
= 0;
4598 mouse_keys
->iMaxSpeed
= 360;
4599 mouse_keys
->iTimeToMaxSpeed
= 1000;
4600 mouse_keys
->iCtrlSpeed
= 0;
4601 mouse_keys
->dwReserved1
= 0;
4602 mouse_keys
->dwReserved2
= 0;
4608 WINE_SPI_FIXME(SPI_SETMOUSEKEYS
);
4610 case SPI_GETSHOWSOUNDS
:
4611 ret
= get_entry( &entry_SHOWSOUNDS
, val
, ptr
);
4613 case SPI_SETSHOWSOUNDS
:
4614 ret
= set_entry( &entry_SHOWSOUNDS
, val
, ptr
, winini
);
4616 case SPI_GETSTICKYKEYS
:
4618 STICKYKEYS
*sticky_keys
= ptr
;
4619 WARN("SPI_GETSTICKYKEYS not fully implemented\n");
4620 if (sticky_keys
&& sticky_keys
->cbSize
== sizeof(STICKYKEYS
))
4622 /* Indicate that no StickyKeys feature available */
4623 sticky_keys
->dwFlags
= 0;
4629 WINE_SPI_FIXME(SPI_SETSTICKYKEYS
);
4631 case SPI_GETACCESSTIMEOUT
:
4633 ACCESSTIMEOUT
*access_timeout
= ptr
;
4634 WARN("SPI_GETACCESSTIMEOUT not fully implemented\n");
4635 if (access_timeout
&& access_timeout
->cbSize
== sizeof(ACCESSTIMEOUT
))
4637 /* Indicate that no accessibility features timeout is available */
4638 access_timeout
->dwFlags
= 0;
4639 access_timeout
->iTimeOutMSec
= 0;
4645 WINE_SPI_FIXME(SPI_SETACCESSTIMEOUT
);
4647 case SPI_GETSERIALKEYS
:
4649 LPSERIALKEYSW serial_keys
= ptr
;
4650 WARN("SPI_GETSERIALKEYS not fully implemented\n");
4651 if (serial_keys
&& serial_keys
->cbSize
== sizeof(SERIALKEYSW
))
4653 /* Indicate that no SerialKeys feature available */
4654 serial_keys
->dwFlags
= 0;
4655 serial_keys
->lpszActivePort
= NULL
;
4656 serial_keys
->lpszPort
= NULL
;
4657 serial_keys
->iBaudRate
= 0;
4658 serial_keys
->iPortState
= 0;
4664 WINE_SPI_FIXME(SPI_SETSERIALKEYS
);
4666 case SPI_GETSOUNDSENTRY
:
4668 SOUNDSENTRYW
*sound_sentry
= ptr
;
4669 WARN("SPI_GETSOUNDSENTRY not fully implemented\n");
4670 if (sound_sentry
&& sound_sentry
->cbSize
== sizeof(SOUNDSENTRYW
))
4672 /* Indicate that no SoundSentry feature available */
4673 sound_sentry
->dwFlags
= 0;
4674 sound_sentry
->iFSTextEffect
= 0;
4675 sound_sentry
->iFSTextEffectMSec
= 0;
4676 sound_sentry
->iFSTextEffectColorBits
= 0;
4677 sound_sentry
->iFSGrafEffect
= 0;
4678 sound_sentry
->iFSGrafEffectMSec
= 0;
4679 sound_sentry
->iFSGrafEffectColor
= 0;
4680 sound_sentry
->iWindowsEffect
= 0;
4681 sound_sentry
->iWindowsEffectMSec
= 0;
4682 sound_sentry
->lpszWindowsEffectDLL
= 0;
4683 sound_sentry
->iWindowsEffectOrdinal
= 0;
4689 WINE_SPI_FIXME(SPI_SETSOUNDSENTRY
);
4691 case SPI_GETHIGHCONTRAST
:
4693 HIGHCONTRASTW
*high_contrast
= ptr
;
4694 WARN("SPI_GETHIGHCONTRAST not fully implemented\n");
4695 if (high_contrast
&& high_contrast
->cbSize
== sizeof(HIGHCONTRASTW
))
4697 /* Indicate that no high contrast feature available */
4698 high_contrast
->dwFlags
= 0;
4699 high_contrast
->lpszDefaultScheme
= NULL
;
4705 WINE_SPI_FIXME(SPI_SETHIGHCONTRAST
);
4707 case SPI_GETKEYBOARDPREF
:
4708 ret
= get_entry( &entry_KEYBOARDPREF
, val
, ptr
);
4710 case SPI_SETKEYBOARDPREF
:
4711 ret
= set_entry( &entry_KEYBOARDPREF
, val
, ptr
, winini
);
4713 case SPI_GETSCREENREADER
:
4714 ret
= get_entry( &entry_SCREENREADER
, val
, ptr
);
4716 case SPI_SETSCREENREADER
:
4717 ret
= set_entry( &entry_SCREENREADER
, val
, ptr
, winini
);
4720 case SPI_GETANIMATION
:
4722 ANIMATIONINFO
*anim_info
= ptr
;
4724 /* Tell it "disabled" */
4725 if (anim_info
&& anim_info
->cbSize
== sizeof(ANIMATIONINFO
))
4727 /* Minimize and restore animation is disabled (nonzero == enabled) */
4728 anim_info
->iMinAnimate
= 0;
4734 WINE_SPI_WARN(SPI_SETANIMATION
);
4736 case SPI_GETFONTSMOOTHING
:
4737 ret
= get_entry( &entry_FONTSMOOTHING
, val
, ptr
);
4738 if (ret
) *(UINT
*)ptr
= (*(UINT
*)ptr
!= 0);
4740 case SPI_SETFONTSMOOTHING
:
4741 val
= val
? 2 : 0; /* Win NT4/2k/XP behavior */
4742 ret
= set_entry( &entry_FONTSMOOTHING
, val
, ptr
, winini
);
4744 case SPI_SETDRAGWIDTH
:
4745 ret
= set_entry( &entry_DRAGWIDTH
, val
, ptr
, winini
);
4747 case SPI_SETDRAGHEIGHT
:
4748 ret
= set_entry( &entry_DRAGHEIGHT
, val
, ptr
, winini
);
4751 WINE_SPI_FIXME(SPI_SETHANDHELD
);
4752 WINE_SPI_FIXME(SPI_GETLOWPOWERTIMEOUT
);
4753 WINE_SPI_FIXME(SPI_GETPOWEROFFTIMEOUT
);
4754 WINE_SPI_FIXME(SPI_SETLOWPOWERTIMEOUT
);
4755 WINE_SPI_FIXME(SPI_SETPOWEROFFTIMEOUT
);
4757 case SPI_GETLOWPOWERACTIVE
:
4758 ret
= get_entry( &entry_LOWPOWERACTIVE
, val
, ptr
);
4760 case SPI_SETLOWPOWERACTIVE
:
4761 ret
= set_entry( &entry_LOWPOWERACTIVE
, val
, ptr
, winini
);
4763 case SPI_GETPOWEROFFACTIVE
:
4764 ret
= get_entry( &entry_POWEROFFACTIVE
, val
, ptr
);
4766 case SPI_SETPOWEROFFACTIVE
:
4767 ret
= set_entry( &entry_POWEROFFACTIVE
, val
, ptr
, winini
);
4770 WINE_SPI_FIXME(SPI_SETCURSORS
);
4771 WINE_SPI_FIXME(SPI_SETICONS
);
4773 case SPI_GETDEFAULTINPUTLANG
:
4774 ret
= NtUserGetKeyboardLayout(0) != 0;
4777 WINE_SPI_FIXME(SPI_SETDEFAULTINPUTLANG
);
4778 WINE_SPI_FIXME(SPI_SETLANGTOGGLE
);
4780 case SPI_GETWINDOWSEXTENSION
:
4781 WARN( "pretend no support for Win9x Plus! for now.\n" );
4782 ret
= FALSE
; /* yes, this is the result value */
4784 case SPI_SETMOUSETRAILS
:
4785 ret
= set_entry( &entry_MOUSETRAILS
, val
, ptr
, winini
);
4787 case SPI_GETMOUSETRAILS
:
4788 ret
= get_entry( &entry_MOUSETRAILS
, val
, ptr
);
4790 case SPI_GETSNAPTODEFBUTTON
:
4791 ret
= get_entry( &entry_SNAPTODEFBUTTON
, val
, ptr
);
4793 case SPI_SETSNAPTODEFBUTTON
:
4794 ret
= set_entry( &entry_SNAPTODEFBUTTON
, val
, ptr
, winini
);
4796 case SPI_SETSCREENSAVERRUNNING
:
4797 ret
= set_entry( &entry_SCREENSAVERRUNNING
, val
, ptr
, winini
);
4799 case SPI_GETMOUSEHOVERWIDTH
:
4800 ret
= get_entry( &entry_MOUSEHOVERWIDTH
, val
, ptr
);
4802 case SPI_SETMOUSEHOVERWIDTH
:
4803 ret
= set_entry( &entry_MOUSEHOVERWIDTH
, val
, ptr
, winini
);
4805 case SPI_GETMOUSEHOVERHEIGHT
:
4806 ret
= get_entry( &entry_MOUSEHOVERHEIGHT
, val
, ptr
);
4808 case SPI_SETMOUSEHOVERHEIGHT
:
4809 ret
= set_entry( &entry_MOUSEHOVERHEIGHT
, val
, ptr
, winini
);
4811 case SPI_GETMOUSEHOVERTIME
:
4812 ret
= get_entry( &entry_MOUSEHOVERTIME
, val
, ptr
);
4814 case SPI_SETMOUSEHOVERTIME
:
4815 ret
= set_entry( &entry_MOUSEHOVERTIME
, val
, ptr
, winini
);
4817 case SPI_GETWHEELSCROLLLINES
:
4818 ret
= get_entry( &entry_WHEELSCROLLLINES
, val
, ptr
);
4820 case SPI_SETWHEELSCROLLLINES
:
4821 ret
= set_entry( &entry_WHEELSCROLLLINES
, val
, ptr
, winini
);
4823 case SPI_GETMENUSHOWDELAY
:
4824 ret
= get_entry( &entry_MENUSHOWDELAY
, val
, ptr
);
4826 case SPI_SETMENUSHOWDELAY
:
4827 ret
= set_entry( &entry_MENUSHOWDELAY
, val
, ptr
, winini
);
4829 case SPI_GETWHEELSCROLLCHARS
:
4830 ret
= get_entry( &entry_WHEELSCROLLCHARS
, val
, ptr
);
4832 case SPI_SETWHEELSCROLLCHARS
:
4833 ret
= set_entry( &entry_WHEELSCROLLCHARS
, val
, ptr
, winini
);
4836 WINE_SPI_FIXME(SPI_GETSHOWIMEUI
);
4837 WINE_SPI_FIXME(SPI_SETSHOWIMEUI
);
4839 case SPI_GETMOUSESPEED
:
4840 ret
= get_entry( &entry_MOUSESPEED
, val
, ptr
);
4842 case SPI_SETMOUSESPEED
:
4843 ret
= set_entry( &entry_MOUSESPEED
, val
, ptr
, winini
);
4845 case SPI_GETSCREENSAVERRUNNING
:
4846 ret
= get_entry( &entry_SCREENSAVERRUNNING
, val
, ptr
);
4848 case SPI_GETDESKWALLPAPER
:
4849 ret
= get_entry( &entry_DESKWALLPAPER
, val
, ptr
);
4851 case SPI_GETACTIVEWINDOWTRACKING
:
4852 ret
= get_entry( &entry_ACTIVEWINDOWTRACKING
, val
, ptr
);
4854 case SPI_SETACTIVEWINDOWTRACKING
:
4855 ret
= set_entry( &entry_ACTIVEWINDOWTRACKING
, val
, ptr
, winini
);
4857 case SPI_GETMENUANIMATION
:
4858 ret
= get_entry( &entry_MENUANIMATION
, val
, ptr
);
4860 case SPI_SETMENUANIMATION
:
4861 ret
= set_entry( &entry_MENUANIMATION
, val
, ptr
, winini
);
4863 case SPI_GETCOMBOBOXANIMATION
:
4864 ret
= get_entry( &entry_COMBOBOXANIMATION
, val
, ptr
);
4866 case SPI_SETCOMBOBOXANIMATION
:
4867 ret
= set_entry( &entry_COMBOBOXANIMATION
, val
, ptr
, winini
);
4869 case SPI_GETLISTBOXSMOOTHSCROLLING
:
4870 ret
= get_entry( &entry_LISTBOXSMOOTHSCROLLING
, val
, ptr
);
4872 case SPI_SETLISTBOXSMOOTHSCROLLING
:
4873 ret
= set_entry( &entry_LISTBOXSMOOTHSCROLLING
, val
, ptr
, winini
);
4875 case SPI_GETGRADIENTCAPTIONS
:
4876 ret
= get_entry( &entry_GRADIENTCAPTIONS
, val
, ptr
);
4878 case SPI_SETGRADIENTCAPTIONS
:
4879 ret
= set_entry( &entry_GRADIENTCAPTIONS
, val
, ptr
, winini
);
4881 case SPI_GETKEYBOARDCUES
:
4882 ret
= get_entry( &entry_KEYBOARDCUES
, val
, ptr
);
4884 case SPI_SETKEYBOARDCUES
:
4885 ret
= set_entry( &entry_KEYBOARDCUES
, val
, ptr
, winini
);
4887 case SPI_GETACTIVEWNDTRKZORDER
:
4888 ret
= get_entry( &entry_ACTIVEWNDTRKZORDER
, val
, ptr
);
4890 case SPI_SETACTIVEWNDTRKZORDER
:
4891 ret
= set_entry( &entry_ACTIVEWNDTRKZORDER
, val
, ptr
, winini
);
4893 case SPI_GETHOTTRACKING
:
4894 ret
= get_entry( &entry_HOTTRACKING
, val
, ptr
);
4896 case SPI_SETHOTTRACKING
:
4897 ret
= set_entry( &entry_HOTTRACKING
, val
, ptr
, winini
);
4899 case SPI_GETMENUFADE
:
4900 ret
= get_entry( &entry_MENUFADE
, val
, ptr
);
4902 case SPI_SETMENUFADE
:
4903 ret
= set_entry( &entry_MENUFADE
, val
, ptr
, winini
);
4905 case SPI_GETSELECTIONFADE
:
4906 ret
= get_entry( &entry_SELECTIONFADE
, val
, ptr
);
4908 case SPI_SETSELECTIONFADE
:
4909 ret
= set_entry( &entry_SELECTIONFADE
, val
, ptr
, winini
);
4911 case SPI_GETTOOLTIPANIMATION
:
4912 ret
= get_entry( &entry_TOOLTIPANIMATION
, val
, ptr
);
4914 case SPI_SETTOOLTIPANIMATION
:
4915 ret
= set_entry( &entry_TOOLTIPANIMATION
, val
, ptr
, winini
);
4917 case SPI_GETTOOLTIPFADE
:
4918 ret
= get_entry( &entry_TOOLTIPFADE
, val
, ptr
);
4920 case SPI_SETTOOLTIPFADE
:
4921 ret
= set_entry( &entry_TOOLTIPFADE
, val
, ptr
, winini
);
4923 case SPI_GETCURSORSHADOW
:
4924 ret
= get_entry( &entry_CURSORSHADOW
, val
, ptr
);
4926 case SPI_SETCURSORSHADOW
:
4927 ret
= set_entry( &entry_CURSORSHADOW
, val
, ptr
, winini
);
4929 case SPI_GETMOUSESONAR
:
4930 ret
= get_entry( &entry_MOUSESONAR
, val
, ptr
);
4932 case SPI_SETMOUSESONAR
:
4933 ret
= set_entry( &entry_MOUSESONAR
, val
, ptr
, winini
);
4935 case SPI_GETMOUSECLICKLOCK
:
4936 ret
= get_entry( &entry_MOUSECLICKLOCK
, val
, ptr
);
4938 case SPI_SETMOUSECLICKLOCK
:
4939 ret
= set_entry( &entry_MOUSECLICKLOCK
, val
, ptr
, winini
);
4941 case SPI_GETMOUSEVANISH
:
4942 ret
= get_entry( &entry_MOUSEVANISH
, val
, ptr
);
4944 case SPI_SETMOUSEVANISH
:
4945 ret
= set_entry( &entry_MOUSEVANISH
, val
, ptr
, winini
);
4947 case SPI_GETFLATMENU
:
4948 ret
= get_entry( &entry_FLATMENU
, val
, ptr
);
4950 case SPI_SETFLATMENU
:
4951 ret
= set_entry( &entry_FLATMENU
, val
, ptr
, winini
);
4953 case SPI_GETDROPSHADOW
:
4954 ret
= get_entry( &entry_DROPSHADOW
, val
, ptr
);
4956 case SPI_SETDROPSHADOW
:
4957 ret
= set_entry( &entry_DROPSHADOW
, val
, ptr
, winini
);
4959 case SPI_GETBLOCKSENDINPUTRESETS
:
4960 ret
= get_entry( &entry_BLOCKSENDINPUTRESETS
, val
, ptr
);
4962 case SPI_SETBLOCKSENDINPUTRESETS
:
4963 ret
= set_entry( &entry_BLOCKSENDINPUTRESETS
, val
, ptr
, winini
);
4965 case SPI_GETUIEFFECTS
:
4966 ret
= get_entry( &entry_UIEFFECTS
, val
, ptr
);
4968 case SPI_SETUIEFFECTS
:
4969 /* FIXME: this probably should mask other UI effect values when unset */
4970 ret
= set_entry( &entry_UIEFFECTS
, val
, ptr
, winini
);
4972 case SPI_GETDISABLEOVERLAPPEDCONTENT
:
4973 ret
= get_entry( &entry_DISABLEOVERLAPPEDCONTENT
, val
, ptr
);
4975 case SPI_SETDISABLEOVERLAPPEDCONTENT
:
4976 ret
= set_entry( &entry_DISABLEOVERLAPPEDCONTENT
, val
, ptr
, winini
);
4978 case SPI_GETCLIENTAREAANIMATION
:
4979 ret
= get_entry( &entry_CLIENTAREAANIMATION
, val
, ptr
);
4981 case SPI_SETCLIENTAREAANIMATION
:
4982 ret
= set_entry( &entry_CLIENTAREAANIMATION
, val
, ptr
, winini
);
4984 case SPI_GETCLEARTYPE
:
4985 ret
= get_entry( &entry_CLEARTYPE
, val
, ptr
);
4987 case SPI_SETCLEARTYPE
:
4988 ret
= set_entry( &entry_CLEARTYPE
, val
, ptr
, winini
);
4990 case SPI_GETSPEECHRECOGNITION
:
4991 ret
= get_entry( &entry_SPEECHRECOGNITION
, val
, ptr
);
4993 case SPI_SETSPEECHRECOGNITION
:
4994 ret
= set_entry( &entry_SPEECHRECOGNITION
, val
, ptr
, winini
);
4996 case SPI_GETFOREGROUNDLOCKTIMEOUT
:
4997 ret
= get_entry( &entry_FOREGROUNDLOCKTIMEOUT
, val
, ptr
);
4999 case SPI_SETFOREGROUNDLOCKTIMEOUT
:
5000 /* FIXME: this should check that the calling thread
5001 * is able to change the foreground window */
5002 ret
= set_entry( &entry_FOREGROUNDLOCKTIMEOUT
, val
, ptr
, winini
);
5004 case SPI_GETACTIVEWNDTRKTIMEOUT
:
5005 ret
= get_entry( &entry_ACTIVEWNDTRKTIMEOUT
, val
, ptr
);
5007 case SPI_SETACTIVEWNDTRKTIMEOUT
:
5008 ret
= get_entry( &entry_ACTIVEWNDTRKTIMEOUT
, val
, ptr
);
5010 case SPI_GETFOREGROUNDFLASHCOUNT
:
5011 ret
= get_entry( &entry_FOREGROUNDFLASHCOUNT
, val
, ptr
);
5013 case SPI_SETFOREGROUNDFLASHCOUNT
:
5014 ret
= set_entry( &entry_FOREGROUNDFLASHCOUNT
, val
, ptr
, winini
);
5016 case SPI_GETCARETWIDTH
:
5017 ret
= get_entry( &entry_CARETWIDTH
, val
, ptr
);
5019 case SPI_SETCARETWIDTH
:
5020 ret
= set_entry( &entry_CARETWIDTH
, val
, ptr
, winini
);
5022 case SPI_GETMOUSECLICKLOCKTIME
:
5023 ret
= get_entry( &entry_MOUSECLICKLOCKTIME
, val
, ptr
);
5025 case SPI_SETMOUSECLICKLOCKTIME
:
5026 ret
= set_entry( &entry_MOUSECLICKLOCKTIME
, val
, ptr
, winini
);
5028 case SPI_GETFONTSMOOTHINGTYPE
:
5029 ret
= get_entry( &entry_FONTSMOOTHINGTYPE
, val
, ptr
);
5031 case SPI_SETFONTSMOOTHINGTYPE
:
5032 ret
= set_entry( &entry_FONTSMOOTHINGTYPE
, val
, ptr
, winini
);
5034 case SPI_GETFONTSMOOTHINGCONTRAST
:
5035 ret
= get_entry( &entry_FONTSMOOTHINGCONTRAST
, val
, ptr
);
5037 case SPI_SETFONTSMOOTHINGCONTRAST
:
5038 ret
= set_entry( &entry_FONTSMOOTHINGCONTRAST
, val
, ptr
, winini
);
5040 case SPI_GETFOCUSBORDERWIDTH
:
5041 ret
= get_entry( &entry_FOCUSBORDERWIDTH
, val
, ptr
);
5043 case SPI_GETFOCUSBORDERHEIGHT
:
5044 ret
= get_entry( &entry_FOCUSBORDERHEIGHT
, val
, ptr
);
5046 case SPI_SETFOCUSBORDERWIDTH
:
5047 ret
= set_entry( &entry_FOCUSBORDERWIDTH
, val
, ptr
, winini
);
5049 case SPI_SETFOCUSBORDERHEIGHT
:
5050 ret
= set_entry( &entry_FOCUSBORDERHEIGHT
, val
, ptr
, winini
);
5052 case SPI_GETFONTSMOOTHINGORIENTATION
:
5053 ret
= get_entry( &entry_FONTSMOOTHINGORIENTATION
, val
, ptr
);
5055 case SPI_SETFONTSMOOTHINGORIENTATION
:
5056 ret
= set_entry( &entry_FONTSMOOTHINGORIENTATION
, val
, ptr
, winini
);
5058 case SPI_GETAUDIODESCRIPTION
:
5060 AUDIODESCRIPTION
*audio
= ptr
;
5061 if (audio
&& audio
->cbSize
== sizeof(AUDIODESCRIPTION
) && val
== sizeof(AUDIODESCRIPTION
) )
5063 ret
= get_entry( &entry_AUDIODESC_ON
, 0, &audio
->Enabled
) &&
5064 get_entry( &entry_AUDIODESC_LOCALE
, 0, &audio
->Locale
);
5068 case SPI_SETAUDIODESCRIPTION
:
5070 AUDIODESCRIPTION
*audio
= ptr
;
5071 if (audio
&& audio
->cbSize
== sizeof(AUDIODESCRIPTION
) && val
== sizeof(AUDIODESCRIPTION
) )
5073 ret
= set_entry( &entry_AUDIODESC_ON
, 0, &audio
->Enabled
, winini
) &&
5074 set_entry( &entry_AUDIODESC_LOCALE
, 0, &audio
->Locale
, winini
);
5079 FIXME( "Unknown action: %u\n", action
);
5080 RtlSetLastWin32Error( ERROR_INVALID_SPI_VALUE
);
5085 if (ret
&& (winini
& SPIF_UPDATEINIFILE
))
5087 static const WCHAR emptyW
[1];
5088 if (winini
& (SPIF_SENDWININICHANGE
| SPIF_SENDCHANGE
))
5089 send_message_timeout( HWND_BROADCAST
, WM_SETTINGCHANGE
, action
, (LPARAM
) emptyW
,
5090 SMTO_ABORTIFHUNG
, 2000, FALSE
);
5092 TRACE( "(%u, %u, %p, %u) ret %d\n", action
, val
, ptr
, winini
, ret
);
5095 #undef WINE_SPI_FIXME
5096 #undef WINE_SPI_WARN
5099 int get_system_metrics( int index
)
5101 NONCLIENTMETRICSW ncm
;
5102 MINIMIZEDMETRICS mm
;
5108 /* some metrics are dynamic */
5113 get_entry( &entry_SCROLLWIDTH
, 0, &ret
);
5114 return max( ret
, 8 );
5116 ncm
.cbSize
= sizeof(ncm
);
5117 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5118 return ncm
.iCaptionHeight
+ 1;
5121 /* SM_C{X,Y}BORDER always returns 1 regardless of 'BorderWidth' value in registry */
5130 get_entry( &entry_SCROLLHEIGHT
, 0, &ret
);
5131 return max( ret
, 8 );
5134 return map_to_dpi( 32, get_system_dpi() );
5137 ret
= map_to_dpi( 32, get_system_dpi() );
5138 if (ret
>= 64) return 64;
5139 if (ret
>= 48) return 48;
5142 ncm
.cbSize
= sizeof(ncm
);
5143 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5144 return ncm
.iMenuHeight
+ 1;
5145 case SM_CXFULLSCREEN
:
5146 /* see the remark for SM_CXMAXIMIZED, at least this formulation is correct */
5147 return get_system_metrics( SM_CXMAXIMIZED
) - 2 * get_system_metrics( SM_CXFRAME
);
5148 case SM_CYFULLSCREEN
:
5149 /* see the remark for SM_CYMAXIMIZED, at least this formulation is
5151 return get_system_metrics( SM_CYMAXIMIZED
) - get_system_metrics( SM_CYMIN
);
5152 case SM_CYKANJIWINDOW
:
5154 case SM_MOUSEPRESENT
:
5159 get_entry( &entry_MOUSEBUTTONSWAP
, 0, &ret
);
5167 ncm
.cbSize
= sizeof(ncm
);
5168 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5169 hdc
= get_display_dc();
5170 get_text_metr_size( hdc
, &ncm
.lfCaptionFont
, NULL
, &ret
);
5171 release_display_dc( hdc
);
5172 return 3 * ncm
.iCaptionWidth
+ ncm
.iCaptionHeight
+ 4 * ret
+
5173 2 * get_system_metrics( SM_CXFRAME
) + 4;
5175 return get_system_metrics( SM_CYCAPTION
) + 2 * get_system_metrics( SM_CYFRAME
);
5177 get_entry( &entry_CAPTIONWIDTH
, 0, &ret
);
5178 return max( ret
, 8 );
5180 ncm
.cbSize
= sizeof(ncm
);
5181 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5182 return ncm
.iCaptionHeight
;
5184 get_entry( &entry_BORDER
, 0, &ret
);
5185 ret
= max( ret
, 1 );
5186 return get_system_metrics( SM_CXDLGFRAME
) + ret
;
5188 get_entry( &entry_BORDER
, 0, &ret
);
5189 ret
= max( ret
, 1 );
5190 return get_system_metrics( SM_CYDLGFRAME
) + ret
;
5192 return get_system_metrics( SM_CXMIN
);
5194 return get_system_metrics( SM_CYMIN
);
5195 case SM_CXDOUBLECLK
:
5196 get_entry( &entry_DOUBLECLKWIDTH
, 0, &ret
);
5198 case SM_CYDOUBLECLK
:
5199 get_entry( &entry_DOUBLECLKHEIGHT
, 0, &ret
);
5201 case SM_CXICONSPACING
:
5202 im
.cbSize
= sizeof(im
);
5203 NtUserSystemParametersInfo( SPI_GETICONMETRICS
, sizeof(im
), &im
, 0 );
5204 return im
.iHorzSpacing
;
5205 case SM_CYICONSPACING
:
5206 im
.cbSize
= sizeof(im
);
5207 NtUserSystemParametersInfo( SPI_GETICONMETRICS
, sizeof(im
), &im
, 0 );
5208 return im
.iVertSpacing
;
5209 case SM_MENUDROPALIGNMENT
:
5210 NtUserSystemParametersInfo( SPI_GETMENUDROPALIGNMENT
, 0, &ret
, 0 );
5214 case SM_DBCSENABLED
:
5215 return ansi_cp
.MaximumCharacterSize
> 1;
5216 case SM_CMOUSEBUTTONS
:
5221 return get_system_metrics( SM_CXBORDER
) + 1;
5223 return get_system_metrics( SM_CYBORDER
) + 1;
5224 case SM_CXMINSPACING
:
5225 mm
.cbSize
= sizeof(mm
);
5226 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(mm
), &mm
, 0 );
5227 return get_system_metrics( SM_CXMINIMIZED
) + mm
.iHorzGap
;
5228 case SM_CYMINSPACING
:
5229 mm
.cbSize
= sizeof(mm
);
5230 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(mm
), &mm
, 0 );
5231 return get_system_metrics( SM_CYMINIMIZED
) + mm
.iVertGap
;
5234 return map_to_dpi( 16, get_system_dpi() ) & ~1;
5235 case SM_CYSMCAPTION
:
5236 ncm
.cbSize
= sizeof(ncm
);
5237 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5238 return ncm
.iSmCaptionHeight
+ 1;
5240 get_entry( &entry_SMCAPTIONWIDTH
, 0, &ret
);
5243 ncm
.cbSize
= sizeof(ncm
);
5244 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5245 return ncm
.iSmCaptionHeight
;
5247 get_entry( &entry_MENUWIDTH
, 0, &ret
);
5250 ncm
.cbSize
= sizeof(ncm
);
5251 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5252 return ncm
.iMenuHeight
;
5254 mm
.cbSize
= sizeof(mm
);
5255 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(mm
), &mm
, 0 );
5257 case SM_CXMINIMIZED
:
5258 mm
.cbSize
= sizeof(mm
);
5259 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(mm
), &mm
, 0 );
5260 return mm
.iWidth
+ 6;
5261 case SM_CYMINIMIZED
:
5262 ncm
.cbSize
= sizeof(ncm
);
5263 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5264 return ncm
.iCaptionHeight
+ 6;
5266 return get_system_metrics( SM_CXVIRTUALSCREEN
) + 4 + 2 * get_system_metrics( SM_CXFRAME
);
5268 return get_system_metrics( SM_CYVIRTUALSCREEN
) + 4 + 2 * get_system_metrics( SM_CYFRAME
);
5269 case SM_CXMAXIMIZED
:
5270 /* FIXME: subtract the width of any vertical application toolbars*/
5271 return get_system_metrics( SM_CXSCREEN
) + 2 * get_system_metrics( SM_CXFRAME
);
5272 case SM_CYMAXIMIZED
:
5273 /* FIXME: subtract the width of any horizontal application toolbars*/
5274 return get_system_metrics( SM_CYSCREEN
) + 2 * get_system_metrics( SM_CYCAPTION
);
5276 return 3; /* FIXME */
5278 return 0; /* 0 = ok, 1 = failsafe, 2 = failsafe + network */
5280 get_entry( &entry_DRAGWIDTH
, 0, &ret
);
5283 get_entry( &entry_DRAGHEIGHT
, 0, &ret
);
5286 get_entry( &entry_SHOWSOUNDS
, 0, &ret
);
5288 case SM_CXMENUCHECK
:
5289 case SM_CYMENUCHECK
:
5292 ncm
.cbSize
= sizeof(ncm
);
5293 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5294 hdc
= get_display_dc();
5295 get_text_metr_size( hdc
, &ncm
.lfMenuFont
, &tm
, NULL
);
5296 release_display_dc( hdc
);
5297 return tm
.tmHeight
<= 0 ? 13 : ((tm
.tmHeight
+ tm
.tmExternalLeading
+ 1) / 2) * 2 - 1;
5299 case SM_SLOWMACHINE
:
5300 return 0; /* Never true */
5301 case SM_MIDEASTENABLED
:
5302 return 0; /* FIXME */
5303 case SM_MOUSEWHEELPRESENT
:
5306 rect
= get_primary_monitor_rect( get_thread_dpi() );
5307 return rect
.right
- rect
.left
;
5309 rect
= get_primary_monitor_rect( get_thread_dpi() );
5310 return rect
.bottom
- rect
.top
;
5311 case SM_XVIRTUALSCREEN
:
5312 rect
= get_virtual_screen_rect( get_thread_dpi() );
5314 case SM_YVIRTUALSCREEN
:
5315 rect
= get_virtual_screen_rect( get_thread_dpi() );
5317 case SM_CXVIRTUALSCREEN
:
5318 rect
= get_virtual_screen_rect( get_thread_dpi() );
5319 return rect
.right
- rect
.left
;
5320 case SM_CYVIRTUALSCREEN
:
5321 rect
= get_virtual_screen_rect( get_thread_dpi() );
5322 return rect
.bottom
- rect
.top
;
5324 if (!lock_display_devices()) return FALSE
;
5325 ret
= active_monitor_count();
5326 unlock_display_devices();
5328 case SM_SAMEDISPLAYFORMAT
:
5331 return 0; /* FIXME */
5332 case SM_CXFOCUSBORDER
:
5333 case SM_CYFOCUSBORDER
:
5336 case SM_MEDIACENTER
:
5345 static int get_system_metrics_for_dpi( int index
, unsigned int dpi
)
5347 NONCLIENTMETRICSW ncm
;
5352 /* some metrics are dynamic */
5357 get_entry_dpi( &entry_SCROLLWIDTH
, 0, &ret
, dpi
);
5358 return max( ret
, 8 );
5360 ncm
.cbSize
= sizeof(ncm
);
5361 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5362 return ncm
.iCaptionHeight
+ 1;
5367 get_entry_dpi( &entry_SCROLLHEIGHT
, 0, &ret
, dpi
);
5368 return max( ret
, 8 );
5371 return map_to_dpi( 32, dpi
);
5374 ret
= map_to_dpi( 32, dpi
);
5375 if (ret
>= 64) return 64;
5376 if (ret
>= 48) return 48;
5379 ncm
.cbSize
= sizeof(ncm
);
5380 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5381 return ncm
.iMenuHeight
+ 1;
5383 get_entry_dpi( &entry_CAPTIONWIDTH
, 0, &ret
, dpi
);
5384 return max( ret
, 8 );
5386 ncm
.cbSize
= sizeof(ncm
);
5387 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5388 return ncm
.iCaptionHeight
;
5390 get_entry_dpi( &entry_BORDER
, 0, &ret
, dpi
);
5391 ret
= max( ret
, 1 );
5392 return get_system_metrics_for_dpi( SM_CXDLGFRAME
, dpi
) + ret
;
5394 get_entry_dpi( &entry_BORDER
, 0, &ret
, dpi
);
5395 ret
= max( ret
, 1 );
5396 return get_system_metrics_for_dpi( SM_CYDLGFRAME
, dpi
) + ret
;
5397 case SM_CXICONSPACING
:
5398 im
.cbSize
= sizeof(im
);
5399 NtUserSystemParametersInfoForDpi( SPI_GETICONMETRICS
, sizeof(im
), &im
, 0, dpi
);
5400 return im
.iHorzSpacing
;
5401 case SM_CYICONSPACING
:
5402 im
.cbSize
= sizeof(im
);
5403 NtUserSystemParametersInfoForDpi( SPI_GETICONMETRICS
, sizeof(im
), &im
, 0, dpi
);
5404 return im
.iVertSpacing
;
5407 return map_to_dpi( 16, dpi
) & ~1;
5408 case SM_CYSMCAPTION
:
5409 ncm
.cbSize
= sizeof(ncm
);
5410 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5411 return ncm
.iSmCaptionHeight
+ 1;
5413 get_entry_dpi( &entry_SMCAPTIONWIDTH
, 0, &ret
, dpi
);
5416 ncm
.cbSize
= sizeof(ncm
);
5417 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5418 return ncm
.iSmCaptionHeight
;
5420 get_entry_dpi( &entry_MENUWIDTH
, 0, &ret
, dpi
);
5423 ncm
.cbSize
= sizeof(ncm
);
5424 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5425 return ncm
.iMenuHeight
;
5426 case SM_CXMENUCHECK
:
5427 case SM_CYMENUCHECK
:
5430 ncm
.cbSize
= sizeof(ncm
);
5431 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5432 hdc
= get_display_dc();
5433 get_text_metr_size( hdc
, &ncm
.lfMenuFont
, &tm
, NULL
);
5434 release_display_dc( hdc
);
5435 return tm
.tmHeight
<= 0 ? 13 : ((tm
.tmHeight
+ tm
.tmExternalLeading
- 1) | 1);
5438 return get_system_metrics( index
);
5442 COLORREF
get_sys_color( int index
)
5446 if (index
>= 0 && index
< ARRAY_SIZE( system_colors
))
5447 get_entry( &system_colors
[index
], 0, &ret
);
5451 HBRUSH
get_55aa_brush(void)
5453 static const WORD pattern
[] = { 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa };
5454 static HBRUSH brush_55aa
;
5458 HBITMAP bitmap
= NtGdiCreateBitmap( 8, 8, 1, 1, pattern
);
5459 HBRUSH brush
= NtGdiCreatePatternBrushInternal( bitmap
, FALSE
, FALSE
);
5460 NtGdiDeleteObjectApp( bitmap
);
5461 make_gdi_object_system( brush
, TRUE
);
5462 if (InterlockedCompareExchangePointer( (void **)&brush_55aa
, brush
, 0 ))
5464 make_gdi_object_system( brush
, FALSE
);
5465 NtGdiDeleteObjectApp( brush
);
5471 HBRUSH
get_sys_color_brush( unsigned int index
)
5473 if (index
== COLOR_55AA_BRUSH
) return get_55aa_brush();
5474 if (index
>= ARRAY_SIZE( system_colors
)) return 0;
5476 if (!system_colors
[index
].brush
)
5478 HBRUSH brush
= NtGdiCreateSolidBrush( get_sys_color( index
), NULL
);
5479 make_gdi_object_system( brush
, TRUE
);
5480 if (InterlockedCompareExchangePointer( (void **)&system_colors
[index
].brush
, brush
, 0 ))
5482 make_gdi_object_system( brush
, FALSE
);
5483 NtGdiDeleteObjectApp( brush
);
5486 return system_colors
[index
].brush
;
5489 HPEN
get_sys_color_pen( unsigned int index
)
5491 if (index
>= ARRAY_SIZE( system_colors
)) return 0;
5493 if (!system_colors
[index
].pen
)
5495 HPEN pen
= NtGdiCreatePen( PS_SOLID
, 1, get_sys_color( index
), NULL
);
5496 make_gdi_object_system( pen
, TRUE
);
5497 if (InterlockedCompareExchangePointer( (void **)&system_colors
[index
].pen
, pen
, 0 ))
5499 make_gdi_object_system( pen
, FALSE
);
5500 NtGdiDeleteObjectApp( pen
);
5503 return system_colors
[index
].pen
;
5506 /**********************************************************************
5507 * NtUserGetDoubleClickTime (win32u.@)
5509 UINT WINAPI
NtUserGetDoubleClickTime(void)
5513 get_entry( &entry_DOUBLECLICKTIME
, 0, &time
);
5514 if (!time
) time
= 500;
5518 /*************************************************************************
5519 * NtUserSetSysColors (win32u.@)
5521 BOOL WINAPI
NtUserSetSysColors( INT count
, const INT
*colors
, const COLORREF
*values
)
5525 if (IS_INTRESOURCE(colors
)) return FALSE
; /* stupid app passes a color instead of an array */
5527 for (i
= 0; i
< count
; i
++)
5528 if (colors
[i
] >= 0 && colors
[i
] <= ARRAY_SIZE( system_colors
))
5529 set_entry( &system_colors
[colors
[i
]], values
[i
], 0, 0 );
5531 /* Send WM_SYSCOLORCHANGE message to all windows */
5532 send_message_timeout( HWND_BROADCAST
, WM_SYSCOLORCHANGE
, 0, 0,
5533 SMTO_ABORTIFHUNG
, 2000, FALSE
);
5534 /* Repaint affected portions of all visible windows */
5535 NtUserRedrawWindow( 0, NULL
, 0, RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_ALLCHILDREN
);
5540 static LONG dpi_awareness
;
5542 /***********************************************************************
5543 * NtUserSetProcessDpiAwarenessContext (win32u.@)
5545 BOOL WINAPI
NtUserSetProcessDpiAwarenessContext( ULONG awareness
, ULONG unknown
)
5549 case NTUSER_DPI_UNAWARE
:
5550 case NTUSER_DPI_SYSTEM_AWARE
:
5551 case NTUSER_DPI_PER_MONITOR_AWARE
:
5552 case NTUSER_DPI_PER_MONITOR_AWARE_V2
:
5553 case NTUSER_DPI_PER_UNAWARE_GDISCALED
:
5556 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
5560 return !InterlockedCompareExchange( &dpi_awareness
, awareness
, 0 );
5563 /***********************************************************************
5564 * NtUserGetProcessDpiAwarenessContext (win32u.@)
5566 ULONG WINAPI
NtUserGetProcessDpiAwarenessContext( HANDLE process
)
5570 if (process
&& process
!= GetCurrentProcess())
5572 WARN( "not supported on other process %p\n", process
);
5573 return NTUSER_DPI_UNAWARE
;
5576 val
= ReadNoFence( &dpi_awareness
);
5577 if (!val
) return NTUSER_DPI_UNAWARE
;
5581 BOOL
message_beep( UINT i
)
5584 NtUserSystemParametersInfo( SPI_GETBEEP
, 0, &active
, FALSE
);
5585 if (active
) user_driver
->pBeep();
5589 static DWORD exiting_thread_id
;
5591 /**********************************************************************
5594 BOOL
is_exiting_thread( DWORD tid
)
5596 return tid
== exiting_thread_id
;
5599 static void thread_detach(void)
5601 struct user_thread_info
*thread_info
= get_user_thread_info();
5603 user_driver
->pThreadDetach();
5605 free( thread_info
->key_state
);
5606 thread_info
->key_state
= 0;
5607 free( thread_info
->rawinput
);
5609 destroy_thread_windows();
5610 cleanup_imm_thread();
5611 NtClose( thread_info
->server_queue
);
5613 exiting_thread_id
= 0;
5616 /***********************************************************************
5617 * NtUserCallNoParam (win32u.@)
5619 ULONG_PTR WINAPI
NtUserCallNoParam( ULONG code
)
5623 case NtUserCallNoParam_DestroyCaret
:
5624 return destroy_caret();
5626 case NtUserCallNoParam_GetDesktopWindow
:
5627 return HandleToUlong( get_desktop_window() );
5629 case NtUserCallNoParam_GetDialogBaseUnits
:
5630 return get_dialog_base_units();
5632 case NtUserCallNoParam_GetInputState
:
5633 return get_input_state();
5635 case NtUserCallNoParam_GetProcessDefaultLayout
:
5636 return process_layout
;
5638 case NtUserCallNoParam_GetProgmanWindow
:
5639 return HandleToUlong( get_progman_window() );
5641 case NtUserCallNoParam_GetShellWindow
:
5642 return HandleToUlong( get_shell_window() );
5644 case NtUserCallNoParam_GetTaskmanWindow
:
5645 return HandleToUlong( get_taskman_window() );
5647 case NtUserCallNoParam_ReleaseCapture
:
5648 return release_capture();
5650 /* temporary exports */
5651 case NtUserExitingThread
:
5652 exiting_thread_id
= GetCurrentThreadId();
5655 case NtUserThreadDetach
:
5660 FIXME( "invalid code %u\n", (int)code
);
5665 /***********************************************************************
5666 * NtUserCallOneParam (win32u.@)
5668 ULONG_PTR WINAPI
NtUserCallOneParam( ULONG_PTR arg
, ULONG code
)
5672 case NtUserCallOneParam_BeginDeferWindowPos
:
5673 return HandleToUlong( begin_defer_window_pos( arg
));
5675 case NtUserCallOneParam_CreateCursorIcon
:
5676 return HandleToUlong( alloc_cursoricon_handle( arg
));
5678 case NtUserCallOneParam_CreateMenu
:
5679 return HandleToUlong( create_menu( arg
) );
5681 case NtUserCallOneParam_EnableDC
:
5682 return set_dce_flags( UlongToHandle(arg
), DCHF_ENABLEDC
);
5684 case NtUserCallOneParam_EnableThunkLock
:
5685 enable_thunk_lock
= arg
;
5688 case NtUserCallOneParam_EnumClipboardFormats
:
5689 return enum_clipboard_formats( arg
);
5691 case NtUserCallOneParam_GetClipCursor
:
5692 return get_clip_cursor( (RECT
*)arg
);
5694 case NtUserCallOneParam_GetCursorPos
:
5695 return get_cursor_pos( (POINT
*)arg
);
5697 case NtUserCallOneParam_GetIconParam
:
5698 return get_icon_param( UlongToHandle(arg
) );
5700 case NtUserCallOneParam_GetMenuItemCount
:
5701 return get_menu_item_count( UlongToHandle(arg
) );
5703 case NtUserCallOneParam_GetSysColor
:
5704 return get_sys_color( arg
);
5706 case NtUserCallOneParam_IsWindowRectFullScreen
:
5707 return is_window_rect_full_screen( (const RECT
*)arg
);
5709 case NtUserCallOneParam_RealizePalette
:
5710 return realize_palette( UlongToHandle(arg
) );
5712 case NtUserCallOneParam_GetPrimaryMonitorRect
:
5713 *(RECT
*)arg
= get_primary_monitor_rect( 0 );
5716 case NtUserCallOneParam_GetSysColorBrush
:
5717 return HandleToUlong( get_sys_color_brush(arg
) );
5719 case NtUserCallOneParam_GetSysColorPen
:
5720 return HandleToUlong( get_sys_color_pen(arg
) );
5722 case NtUserCallOneParam_GetSystemMetrics
:
5723 return get_system_metrics( arg
);
5725 case NtUserCallOneParam_GetVirtualScreenRect
:
5726 *(RECT
*)arg
= get_virtual_screen_rect( 0 );
5729 case NtUserCallOneParam_MessageBeep
:
5730 return message_beep( arg
);
5732 case NtUserCallOneParam_ReplyMessage
:
5733 return reply_message_result( arg
);
5735 case NtUserCallOneParam_SetCaretBlinkTime
:
5736 return set_caret_blink_time( arg
);
5738 case NtUserCallOneParam_SetProcessDefaultLayout
:
5739 process_layout
= arg
;
5742 /* temporary exports */
5743 case NtUserGetDeskPattern
:
5744 return get_entry( &entry_DESKPATTERN
, 256, (WCHAR
*)arg
);
5747 FIXME( "invalid code %u\n", (int)code
);
5752 /***********************************************************************
5753 * NtUserCallTwoParam (win32u.@)
5755 ULONG_PTR WINAPI
NtUserCallTwoParam( ULONG_PTR arg1
, ULONG_PTR arg2
, ULONG code
)
5759 case NtUserCallTwoParam_GetDialogProc
:
5760 return (ULONG_PTR
)get_dialog_proc( (DLGPROC
)arg1
, arg2
);
5762 case NtUserCallTwoParam_GetMenuInfo
:
5763 return get_menu_info( UlongToHandle(arg1
), (MENUINFO
*)arg2
);
5765 case NtUserCallTwoParam_GetMonitorInfo
:
5766 return get_monitor_info( UlongToHandle(arg1
), (MONITORINFO
*)arg2
);
5768 case NtUserCallTwoParam_GetSystemMetricsForDpi
:
5769 return get_system_metrics_for_dpi( arg1
, arg2
);
5771 case NtUserCallTwoParam_MonitorFromRect
:
5772 return HandleToUlong( monitor_from_rect( (const RECT
*)arg1
, arg2
, get_thread_dpi() ));
5774 case NtUserCallTwoParam_SetCaretPos
:
5775 return set_caret_pos( arg1
, arg2
);
5777 case NtUserCallTwoParam_SetIconParam
:
5778 return set_icon_param( UlongToHandle(arg1
), arg2
);
5780 case NtUserCallTwoParam_UnhookWindowsHook
:
5781 return unhook_windows_hook( arg1
, (HOOKPROC
)arg2
);
5783 /* temporary exports */
5784 case NtUserAllocWinProc
:
5785 return (UINT_PTR
)alloc_winproc( (WNDPROC
)arg1
, arg2
);
5788 FIXME( "invalid code %u\n", (int)code
);
5793 /***********************************************************************
5794 * NtUserDisplayConfigGetDeviceInfo (win32u.@)
5796 NTSTATUS WINAPI
NtUserDisplayConfigGetDeviceInfo( DISPLAYCONFIG_DEVICE_INFO_HEADER
*packet
)
5798 NTSTATUS ret
= STATUS_UNSUCCESSFUL
;
5800 TRACE( "packet %p.\n", packet
);
5802 if (!packet
|| packet
->size
< sizeof(*packet
))
5803 return STATUS_UNSUCCESSFUL
;
5805 switch (packet
->type
)
5807 case DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME
:
5809 DISPLAYCONFIG_SOURCE_DEVICE_NAME
*source_name
= (DISPLAYCONFIG_SOURCE_DEVICE_NAME
*)packet
;
5810 struct adapter
*adapter
;
5812 TRACE( "DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME.\n" );
5814 if (packet
->size
< sizeof(*source_name
))
5815 return STATUS_INVALID_PARAMETER
;
5817 if (!lock_display_devices()) return STATUS_UNSUCCESSFUL
;
5819 LIST_FOR_EACH_ENTRY(adapter
, &adapters
, struct adapter
, entry
)
5821 if (source_name
->header
.id
!= adapter
->id
) continue;
5822 if (memcmp( &source_name
->header
.adapterId
, &adapter
->gpu_luid
, sizeof(adapter
->gpu_luid
) )) continue;
5824 lstrcpyW( source_name
->viewGdiDeviceName
, adapter
->dev
.device_name
);
5825 ret
= STATUS_SUCCESS
;
5829 unlock_display_devices();
5832 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME
:
5834 DISPLAYCONFIG_TARGET_DEVICE_NAME
*target_name
= (DISPLAYCONFIG_TARGET_DEVICE_NAME
*)packet
;
5835 char buffer
[ARRAY_SIZE(target_name
->monitorFriendlyDeviceName
)];
5836 struct monitor
*monitor
;
5838 TRACE( "DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME.\n" );
5840 if (packet
->size
< sizeof(*target_name
))
5841 return STATUS_INVALID_PARAMETER
;
5843 if (!lock_display_devices()) return STATUS_UNSUCCESSFUL
;
5845 memset( &target_name
->flags
, 0, sizeof(*target_name
) - offsetof(DISPLAYCONFIG_TARGET_DEVICE_NAME
, flags
) );
5847 LIST_FOR_EACH_ENTRY(monitor
, &monitors
, struct monitor
, entry
)
5849 if (target_name
->header
.id
!= monitor
->output_id
) continue;
5850 if (memcmp( &target_name
->header
.adapterId
, &monitor
->adapter
->gpu_luid
,
5851 sizeof(monitor
->adapter
->gpu_luid
) ))
5854 target_name
->outputTechnology
= DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL
;
5855 snprintf( buffer
, ARRAY_SIZE(buffer
), "Display%u", monitor
->output_id
+ 1 );
5856 asciiz_to_unicode( target_name
->monitorFriendlyDeviceName
, buffer
);
5857 lstrcpyW( target_name
->monitorDevicePath
, monitor
->dev
.interface_name
);
5858 if (monitor
->edid_info
.flags
& MONITOR_INFO_HAS_MONITOR_ID
)
5860 target_name
->edidManufactureId
= monitor
->edid_info
.manufacturer
;
5861 target_name
->edidProductCodeId
= monitor
->edid_info
.product_code
;
5862 target_name
->flags
.edidIdsValid
= 1;
5864 if (monitor
->edid_info
.flags
& MONITOR_INFO_HAS_MONITOR_NAME
)
5866 wcscpy( target_name
->monitorFriendlyDeviceName
, monitor
->edid_info
.monitor_name
);
5867 target_name
->flags
.friendlyNameFromEdid
= 1;
5869 ret
= STATUS_SUCCESS
;
5873 unlock_display_devices();
5876 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE
:
5878 DISPLAYCONFIG_TARGET_PREFERRED_MODE
*preferred_mode
= (DISPLAYCONFIG_TARGET_PREFERRED_MODE
*)packet
;
5879 DISPLAYCONFIG_VIDEO_SIGNAL_INFO
*signal_info
= &preferred_mode
->targetMode
.targetVideoSignalInfo
;
5880 unsigned int i
, display_freq
;
5881 DEVMODEW
*found_mode
= NULL
;
5882 BOOL have_edid_mode
= FALSE
;
5883 struct monitor
*monitor
;
5885 FIXME( "DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE semi-stub.\n" );
5887 if (packet
->size
< sizeof(*preferred_mode
))
5888 return STATUS_INVALID_PARAMETER
;
5890 if (!lock_display_devices()) return STATUS_UNSUCCESSFUL
;
5892 memset( &preferred_mode
->width
, 0, sizeof(*preferred_mode
) - offsetof(DISPLAYCONFIG_TARGET_PREFERRED_MODE
, width
) );
5894 LIST_FOR_EACH_ENTRY(monitor
, &monitors
, struct monitor
, entry
)
5896 if (preferred_mode
->header
.id
!= monitor
->output_id
) continue;
5897 if (memcmp( &preferred_mode
->header
.adapterId
, &monitor
->adapter
->gpu_luid
,
5898 sizeof(monitor
->adapter
->gpu_luid
) ))
5901 for (i
= 0; i
< monitor
->adapter
->mode_count
; ++i
)
5903 DEVMODEW
*mode
= &monitor
->adapter
->modes
[i
];
5905 if (!have_edid_mode
&& monitor
->edid_info
.flags
& MONITOR_INFO_HAS_PREFERRED_MODE
5906 && mode
->dmPelsWidth
== monitor
->edid_info
.preferred_width
5907 && mode
->dmPelsHeight
== monitor
->edid_info
.preferred_height
)
5910 have_edid_mode
= TRUE
;
5913 if (!have_edid_mode
&& (!found_mode
5914 || (mode
->dmPelsWidth
> found_mode
->dmPelsWidth
&& mode
->dmPelsHeight
>= found_mode
->dmPelsHeight
)
5915 || (mode
->dmPelsHeight
> found_mode
->dmPelsHeight
&& mode
->dmPelsWidth
>= found_mode
->dmPelsWidth
)))
5918 if (mode
->dmPelsWidth
== found_mode
->dmPelsWidth
5919 && mode
->dmPelsHeight
== found_mode
->dmPelsHeight
5920 && mode
->dmDisplayFrequency
> found_mode
->dmDisplayFrequency
)
5926 ERR( "No mode found.\n" );
5929 preferred_mode
->width
= found_mode
->dmPelsWidth
;
5930 preferred_mode
->height
= found_mode
->dmPelsHeight
;
5931 display_freq
= found_mode
->dmDisplayFrequency
;
5933 signal_info
->pixelRate
= display_freq
* preferred_mode
->width
* preferred_mode
->height
;
5934 signal_info
->hSyncFreq
.Numerator
= display_freq
* preferred_mode
->width
;
5935 signal_info
->hSyncFreq
.Denominator
= 1;
5936 signal_info
->vSyncFreq
.Numerator
= display_freq
;
5937 signal_info
->vSyncFreq
.Denominator
= 1;
5938 signal_info
->activeSize
.cx
= preferred_mode
->width
;
5939 signal_info
->activeSize
.cy
= preferred_mode
->height
;
5940 signal_info
->totalSize
.cx
= preferred_mode
->width
;
5941 signal_info
->totalSize
.cy
= preferred_mode
->height
;
5942 signal_info
->videoStandard
= D3DKMDT_VSS_OTHER
;
5943 if (!(found_mode
->dmFields
& DM_DISPLAYFLAGS
))
5944 signal_info
->scanLineOrdering
= DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED
;
5945 else if (found_mode
->dmDisplayFlags
& DM_INTERLACED
)
5946 signal_info
->scanLineOrdering
= DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED
;
5948 signal_info
->scanLineOrdering
= DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE
;
5949 ret
= STATUS_SUCCESS
;
5953 unlock_display_devices();
5956 case DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME
:
5958 DISPLAYCONFIG_ADAPTER_NAME
*adapter_name
= (DISPLAYCONFIG_ADAPTER_NAME
*)packet
;
5960 FIXME( "DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME stub.\n" );
5962 if (packet
->size
< sizeof(*adapter_name
))
5963 return STATUS_INVALID_PARAMETER
;
5965 return STATUS_NOT_SUPPORTED
;
5967 case DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE
:
5968 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE
:
5969 case DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION
:
5970 case DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION
:
5971 case DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO
:
5972 case DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE
:
5973 case DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL
:
5975 FIXME( "Unimplemented packet type %u.\n", packet
->type
);
5976 return STATUS_INVALID_PARAMETER
;